/** * Web Component * * Data Subject Request Portal for GDPR rights * * Usage: * * * * Split: translations → dsr-portal-translations.ts * styles + HTML builders → dsr-portal-render.ts */ import type { DSRRequestType } from '@breakpilot/compliance-sdk-types' import { BreakPilotElement } from './base' import { DSR_TRANSLATIONS, type DSRLanguage } from './dsr-portal-translations' import { DSR_PORTAL_STYLES, buildFormHtml, buildSuccessHtml } from './dsr-portal-render' export class DSRPortalElement extends BreakPilotElement { static get observedAttributes(): string[] { return ['api-key', 'api-endpoint', 'tenant-id', 'language'] } private selectedType: DSRRequestType | null = null private name = '' private email = '' private additionalInfo = '' private isSubmitting = false private isSubmitted = false private error: string | null = null private get language(): DSRLanguage { return (this.getAttribute('language') as DSRLanguage) || 'de' } private get t() { return DSR_TRANSLATIONS[this.language] } private handleTypeSelect = (type: DSRRequestType): void => { this.selectedType = type this.render() } private handleSubmit = async (e: Event): Promise => { e.preventDefault() if (!this.selectedType || !this.email || !this.name) { return } this.isSubmitting = true this.error = null this.render() try { // In a real implementation, this would use the client // For now, we simulate a successful submission await new Promise(resolve => setTimeout(resolve, 1000)) this.emit('dsr-submitted', { type: this.selectedType, email: this.email, name: this.name, additionalInfo: this.additionalInfo, }) this.isSubmitted = true } catch (err) { this.error = err instanceof Error ? err.message : 'Ein Fehler ist aufgetreten' } finally { this.isSubmitting = false this.render() } } protected render(): void { if (this.isSubmitted) { this.shadow.innerHTML = buildSuccessHtml(DSR_PORTAL_STYLES, this.t, this.email) } else { this.renderForm() } } private renderForm(): void { this.shadow.innerHTML = buildFormHtml(DSR_PORTAL_STYLES, { t: this.t, selectedType: this.selectedType, name: this.name, email: this.email, additionalInfo: this.additionalInfo, isSubmitting: this.isSubmitting, error: this.error, }) // Bind events const form = this.shadow.getElementById('dsr-form') as HTMLFormElement form.onsubmit = this.handleSubmit const nameInput = this.shadow.getElementById('name-input') as HTMLInputElement nameInput.oninput = e => { this.name = (e.target as HTMLInputElement).value } const emailInput = this.shadow.getElementById('email-input') as HTMLInputElement emailInput.oninput = e => { this.email = (e.target as HTMLInputElement).value } const infoInput = this.shadow.getElementById('info-input') as HTMLTextAreaElement infoInput.oninput = e => { this.additionalInfo = (e.target as HTMLTextAreaElement).value } // Bind radio buttons this.shadow.querySelectorAll('input[name="dsrType"]').forEach(radio => { radio.onchange = () => { this.handleTypeSelect(radio.value as DSRRequestType) } }) } } // Register the custom element if (typeof customElements !== 'undefined') { customElements.define('breakpilot-dsr-portal', DSRPortalElement) }