styling, DateOfBirth corrected
This commit is contained in:
56
frontend/src/app.d.ts
vendored
56
frontend/src/app.d.ts
vendored
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
interface Subscription {
|
interface Subscription {
|
||||||
id: number | -1;
|
id: number | -1;
|
||||||
name: string | "";
|
name: string | '';
|
||||||
details?: string | "";
|
details?: string | '';
|
||||||
conditions?: string | "";
|
conditions?: string | '';
|
||||||
monthly_fee?: number | -1;
|
monthly_fee?: number | -1;
|
||||||
hourly_rate?: number | -1;
|
hourly_rate?: number | -1;
|
||||||
included_hours_per_year?: number | 0;
|
included_hours_per_year?: number | 0;
|
||||||
@@ -14,57 +14,57 @@ interface Subscription {
|
|||||||
interface Membership {
|
interface Membership {
|
||||||
id: number | -1;
|
id: number | -1;
|
||||||
status: number | -1;
|
status: number | -1;
|
||||||
start_date: string | "";
|
start_date: string | '';
|
||||||
end_date: string | "";
|
end_date: string | '';
|
||||||
parent_member_id: number | -1;
|
parent_member_id: number | -1;
|
||||||
subscription_model: Subscription;
|
subscription_model: Subscription;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BankAccount {
|
interface BankAccount {
|
||||||
id: number | -1;
|
id: number | -1;
|
||||||
mandate_date_signed: string | "";
|
mandate_date_signed: string | '';
|
||||||
bank: string | "";
|
bank: string | '';
|
||||||
account_holder_name: string | "";
|
account_holder_name: string | '';
|
||||||
iban: string | "";
|
iban: string | '';
|
||||||
bic: string | "";
|
bic: string | '';
|
||||||
mandate_reference: string | "";
|
mandate_reference: string | '';
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Licence {
|
interface Licence {
|
||||||
id: number | -1;
|
id: number | -1;
|
||||||
status: number | -1;
|
status: number | -1;
|
||||||
licence_number: string | "";
|
licence_number: string | '';
|
||||||
issued_date: string | "";
|
issued_date: string | '';
|
||||||
expiration_date: string | "";
|
expiration_date: string | '';
|
||||||
country: string | "";
|
country: string | '';
|
||||||
licence_categories: LicenceCategory[];
|
licence_categories: LicenceCategory[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LicenceCategory {
|
interface LicenceCategory {
|
||||||
id: number | -1;
|
id: number | -1;
|
||||||
category: string | "";
|
category: string | '';
|
||||||
}
|
}
|
||||||
|
|
||||||
interface User {
|
interface User {
|
||||||
email: string | "";
|
email: string | '';
|
||||||
first_name: string | "";
|
first_name: string | '';
|
||||||
last_name: string | "";
|
last_name: string | '';
|
||||||
phone: string | "";
|
phone: string | '';
|
||||||
notes: string | "";
|
notes: string | '';
|
||||||
address: string | "";
|
address: string | '';
|
||||||
zip_code: string | "";
|
zip_code: string | '';
|
||||||
city: string | "";
|
city: string | '';
|
||||||
status: number | -1;
|
status: number | -1;
|
||||||
id: number | -1;
|
id: number | -1;
|
||||||
role_id: number | -1;
|
role_id: number | -1;
|
||||||
date_of_birth: string | "";
|
dateofbirth: string | '';
|
||||||
company: string | "";
|
company: string | '';
|
||||||
profile_picture: string | "";
|
profile_picture: string | '';
|
||||||
payment_status: number | -1;
|
payment_status: number | -1;
|
||||||
membership: Membership;
|
membership: Membership;
|
||||||
bank_account: BankAccount;
|
bank_account: BankAccount;
|
||||||
licence: Licence;
|
licence: Licence;
|
||||||
notes: string | "";
|
notes: string | '';
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
|||||||
@@ -283,7 +283,6 @@
|
|||||||
|
|
||||||
.input {
|
.input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0.5rem 0;
|
|
||||||
}
|
}
|
||||||
input,
|
input,
|
||||||
textarea,
|
textarea,
|
||||||
@@ -316,7 +315,6 @@
|
|||||||
}
|
}
|
||||||
/* Add consistent spacing between input boxes */
|
/* Add consistent spacing between input boxes */
|
||||||
.input-box {
|
.input-box {
|
||||||
margin: 1rem 0;
|
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
background-color: var(--surface0);
|
background-color: var(--surface0);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
|
|||||||
@@ -28,28 +28,6 @@
|
|||||||
|
|
||||||
<div class="modal-background">
|
<div class="modal-background">
|
||||||
<div transition:modal|global={{ duration: 1000 }} class="modal" role="dialog" aria-modal="true">
|
<div transition:modal|global={{ duration: 1000 }} class="modal" role="dialog" aria-modal="true">
|
||||||
<!-- svelte-ignore a11y-missing-attribute -->
|
|
||||||
<a
|
|
||||||
title={$t('cancel')}
|
|
||||||
class="modal-close"
|
|
||||||
on:click={closeModal}
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
on:keydown={(e) => e.key == 'Enter' && closeModal()}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 384 512"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span class="sr-only">{$t('cancel')}</span>
|
|
||||||
</a>
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
@@ -64,7 +42,7 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background: rgba(30, 30, 46, 0.65); /* var(--base) with 0.75 opacity */
|
background: var(--modal-backdrop); /* var(--base) with 0.75 opacity */
|
||||||
backdrop-filter: blur(4px); /* Optional: adds a slight blur effect */
|
backdrop-filter: blur(4px); /* Optional: adds a slight blur effect */
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -149,7 +127,6 @@
|
|||||||
.modal .container {
|
.modal .container {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
zip_code: '',
|
zip_code: '',
|
||||||
city: '',
|
city: '',
|
||||||
company: '',
|
company: '',
|
||||||
date_of_birth: '',
|
dateofbirth: '',
|
||||||
notes: '',
|
notes: '',
|
||||||
profile_picture: '',
|
profile_picture: '',
|
||||||
payment_status: 0,
|
payment_status: 0,
|
||||||
@@ -297,11 +297,11 @@
|
|||||||
placeholder={$t('placeholder.phone')}
|
placeholder={$t('placeholder.phone')}
|
||||||
/>
|
/>
|
||||||
<InputField
|
<InputField
|
||||||
name="user[date_of_birth]"
|
name="user[dateofbirth]"
|
||||||
type="date"
|
type="date"
|
||||||
label={$t('date_of_birth')}
|
label={$t('dateofbirth')}
|
||||||
bind:value={localUser.date_of_birth}
|
bind:value={localUser.dateofbirth}
|
||||||
placeholder={$t('placeholder.date_of_birth')}
|
placeholder={$t('placeholder.dateofbirth')}
|
||||||
/>
|
/>
|
||||||
<InputField
|
<InputField
|
||||||
name="user[address]"
|
name="user[address]"
|
||||||
@@ -529,7 +529,7 @@
|
|||||||
.category-break {
|
.category-break {
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
background-color: var(--surface0);
|
background-color: var(--overlay0);
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
margin-left: 20%;
|
margin-left: 20%;
|
||||||
width: 60%;
|
width: 60%;
|
||||||
|
|||||||
3
frontend/src/lib/css/styles.min.css
vendored
3
frontend/src/lib/css/styles.min.css
vendored
@@ -25,6 +25,7 @@
|
|||||||
--base: #1e1e2e;
|
--base: #1e1e2e;
|
||||||
--mantle: #181825;
|
--mantle: #181825;
|
||||||
--crust: #11111b;
|
--crust: #11111b;
|
||||||
|
--modal-backdrop: rgba(49, 50, 68, 0.45); /* For Mocha theme */
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@@ -385,8 +386,6 @@ li strong {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin: 10px 0;
|
|
||||||
padding: 10px;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|||||||
@@ -1,179 +1,176 @@
|
|||||||
export default {
|
export default {
|
||||||
userStatus: {
|
userStatus: {
|
||||||
1: "Nicht verifiziert",
|
1: 'Nicht verifiziert',
|
||||||
2: "Verifiziert",
|
2: 'Verifiziert',
|
||||||
3: "Aktiv",
|
3: 'Aktiv',
|
||||||
4: "Passiv",
|
4: 'Passiv',
|
||||||
5: "Deaktiviert",
|
5: 'Deaktiviert'
|
||||||
},
|
},
|
||||||
userRole: {
|
userRole: {
|
||||||
0: "Mitglied",
|
0: 'Mitglied',
|
||||||
1: "Betrachter",
|
1: 'Betrachter',
|
||||||
4: "Bearbeiter",
|
4: 'Bearbeiter',
|
||||||
8: "Administrator",
|
8: 'Administrator'
|
||||||
},
|
},
|
||||||
placeholder: {
|
placeholder: {
|
||||||
password: "Passwort eingeben...",
|
password: 'Passwort eingeben...',
|
||||||
email: "Emailadresse eingeben...",
|
email: 'Emailadresse eingeben...',
|
||||||
company: "Firmennamen eingeben...",
|
company: 'Firmennamen eingeben...',
|
||||||
first_name: "Vornamen eingeben...",
|
first_name: 'Vornamen eingeben...',
|
||||||
last_name: "Nachnamen eingeben...",
|
last_name: 'Nachnamen eingeben...',
|
||||||
phone: "Telefonnummer eingeben...",
|
phone: 'Telefonnummer eingeben...',
|
||||||
address: "Straße und Hausnummer eingeben...",
|
address: 'Straße und Hausnummer eingeben...',
|
||||||
zip_code: "Postleitzahl eingeben...",
|
zip_code: 'Postleitzahl eingeben...',
|
||||||
city: "Wohnort eingeben...",
|
city: 'Wohnort eingeben...',
|
||||||
bank_name: "Namen der Bank eingeben...",
|
bank_name: 'Namen der Bank eingeben...',
|
||||||
parent_member_id: "Mitgliedsnr des Hauptmitglieds eingeben...",
|
parent_member_id: 'Mitgliedsnr des Hauptmitglieds eingeben...',
|
||||||
bank_account_holder: "Namen eingeben...",
|
bank_account_holder: 'Namen eingeben...',
|
||||||
iban: "IBAN eingeben..",
|
iban: 'IBAN eingeben..',
|
||||||
bic: "BIC eingeben(Bei nicht deutschen Konten)...",
|
bic: 'BIC eingeben(Bei nicht deutschen Konten)...',
|
||||||
mandate_reference: "SEPA Mandatsreferenz eingeben..",
|
mandate_reference: 'SEPA Mandatsreferenz eingeben..',
|
||||||
notes: "Deine Notizen zu {name}...",
|
notes: 'Deine Notizen zu {name}...',
|
||||||
licence_number: "Auf dem Führerschein unter Feld 5",
|
licence_number: 'Auf dem Führerschein unter Feld 5',
|
||||||
issued_date: "Ausgabedatum unter Feld 4a",
|
issued_date: 'Ausgabedatum unter Feld 4a',
|
||||||
expiration_date: "Ablaufdatum unter Feld 4b",
|
expiration_date: 'Ablaufdatum unter Feld 4b',
|
||||||
issuing_country: "Ausstellendes Land",
|
issuing_country: 'Ausstellendes Land'
|
||||||
},
|
},
|
||||||
validation: {
|
validation: {
|
||||||
required: "Eingabe benötigt",
|
required: 'Eingabe benötigt',
|
||||||
password: "Password zu kurz, mindestens 8 Zeichen",
|
password: 'Password zu kurz, mindestens 8 Zeichen',
|
||||||
password_match: "Passwörter stimmen nicht überein!",
|
password_match: 'Passwörter stimmen nicht überein!',
|
||||||
phone: "Ungültiges Format(+491738762387 oder 0173850698)",
|
phone: 'Ungültiges Format(+491738762387 oder 0173850698)',
|
||||||
zip_code: "Ungültige Postleitzahl(Nur deutsche Wohnorte sind zulässig)",
|
zip_code: 'Ungültige Postleitzahl(Nur deutsche Wohnorte sind zulässig)',
|
||||||
bic: "Ungültige BIC",
|
bic: 'Ungültige BIC',
|
||||||
iban: "Ungültige IBAN",
|
iban: 'Ungültige IBAN',
|
||||||
date: "Bitte geben Sie ein Datum ein",
|
date: 'Bitte geben Sie ein Datum ein',
|
||||||
email: "Ungültige Emailadresse",
|
email: 'Ungültige Emailadresse',
|
||||||
licence: "Nummer zu kurz(11 Zeichen)",
|
licence: 'Nummer zu kurz(11 Zeichen)'
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
error: {
|
error: {
|
||||||
invalid_json: "JSON Daten sind ungültig",
|
invalid_json: 'JSON Daten sind ungültig',
|
||||||
no_auth_token: "Nicht authorisiert, fehlender oder ungültiger Auth-Token",
|
no_auth_token: 'Nicht authorisiert, fehlender oder ungültiger Auth-Token',
|
||||||
jwt_parsing_error:
|
jwt_parsing_error: 'Nicht authorisiert, Auth-Token konnte nicht gelesen werden',
|
||||||
"Nicht authorisiert, Auth-Token konnte nicht gelesen werden",
|
unauthorized: 'Sie sind nicht befugt diese Handlung durchzuführen',
|
||||||
unauthorized: "Sie sind nicht befugt diese Handlung durchzuführen",
|
|
||||||
internal_server_error:
|
internal_server_error:
|
||||||
"Verdammt, Fehler auf unserer Seite, probieren Sie es nochmal, danach rufen Sie jemanden vom Verein an.",
|
'Verdammt, Fehler auf unserer Seite, probieren Sie es nochmal, danach rufen Sie jemanden vom Verein an.'
|
||||||
},
|
},
|
||||||
validation: {
|
validation: {
|
||||||
invalid_user_id: "Nutzer ID ungültig",
|
invalid_user_id: 'Nutzer ID ungültig',
|
||||||
invalid_subscription_model: "Model nicht gefunden",
|
invalid_subscription_model: 'Model nicht gefunden',
|
||||||
user_not_found: "{field} konnte nicht gefunden werden",
|
user_not_found: '{field} konnte nicht gefunden werden',
|
||||||
invalid_user_data: "Nutzerdaten ungültig",
|
invalid_user_data: 'Nutzerdaten ungültig',
|
||||||
user_not_found_or_wrong_password:
|
user_not_found_or_wrong_password: 'Existiert nicht oder falsches Passwort',
|
||||||
"Existiert nicht oder falsches Passwort",
|
email_already_registered: 'Ein Mitglied wurde schon mit dieser Emailadresse erstellt.',
|
||||||
email_already_registered:
|
alphanumunicode: 'beinhaltet nicht erlaubte Zeichen',
|
||||||
"Ein Mitglied wurde schon mit dieser Emailadresse erstellt.",
|
safe_content: 'I see what you did there! Do not cross this line!',
|
||||||
alphanumunicode: "beinhaltet nicht erlaubte Zeichen",
|
iban: 'Ungültig. Format: DE07123412341234123412',
|
||||||
safe_content: "I see what you did there! Do not cross this line!",
|
bic: 'Ungültig. Format: BELADEBEXXX',
|
||||||
iban: "Ungültig. Format: DE07123412341234123412",
|
email: 'Format ungültig',
|
||||||
bic: "Ungültig. Format: BELADEBEXXX",
|
number: 'Ist keine Nummer',
|
||||||
email: "Format ungültig",
|
euDriversLicence: 'Ist kein europäischer Führerschein',
|
||||||
number: "Ist keine Nummer",
|
lte: 'Ist zu groß/neu',
|
||||||
euDriversLicence: "Ist kein europäischer Führerschein",
|
gt: 'Ist zu klein/alt',
|
||||||
lte: "Ist zu groß/neu",
|
required: 'Feld wird benötigt',
|
||||||
gt: "Ist zu klein/alt",
|
image: 'Dies ist kein Bild',
|
||||||
required: "Feld wird benötigt",
|
alphanum: 'beinhaltet ungültige Zeichen',
|
||||||
image: "Dies ist kein Bild",
|
alphaunicode: 'darf nur aus Buchstaben bestehen'
|
||||||
alphanum: "beinhaltet ungültige Zeichen",
|
}
|
||||||
alphaunicode: "darf nur aus Buchstaben bestehen",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
licenceCategory: {
|
licenceCategory: {
|
||||||
AM: "Mopeds und leichte vierrädrige Kraftfahrzeuge (50ccm, max 45km/h)",
|
AM: 'Mopeds und leichte vierrädrige Kraftfahrzeuge (50ccm, max 45km/h)',
|
||||||
A1: "Leichte Motorräder (125ccm)",
|
A1: 'Leichte Motorräder (125ccm)',
|
||||||
A2: "Motorräder mit mittlerer Leistung (max 35kW)",
|
A2: 'Motorräder mit mittlerer Leistung (max 35kW)',
|
||||||
A: "Motorräder",
|
A: 'Motorräder',
|
||||||
B: "Kraftfahrzeuge ≤ 3500 kg, ≤ 8 Sitzplätze",
|
B: 'Kraftfahrzeuge ≤ 3500 kg, ≤ 8 Sitzplätze',
|
||||||
C1: "Mittelschwere Fahrzeuge -7500 kg",
|
C1: 'Mittelschwere Fahrzeuge -7500 kg',
|
||||||
C: "Schwere Nutzfahrzeuge > 3500 kg",
|
C: 'Schwere Nutzfahrzeuge > 3500 kg',
|
||||||
D1: "Kleinbusse 9-16 Sitzplätze",
|
D1: 'Kleinbusse 9-16 Sitzplätze',
|
||||||
D: "Busse > 8 Sitzplätze",
|
D: 'Busse > 8 Sitzplätze',
|
||||||
BE: "Fahrzeugklasse B mit Anhänger",
|
BE: 'Fahrzeugklasse B mit Anhänger',
|
||||||
C1E: "Fahrzeugklasse C1 mit Anhänger",
|
C1E: 'Fahrzeugklasse C1 mit Anhänger',
|
||||||
CE: "Fahrzeugklasse C mit Anhänger",
|
CE: 'Fahrzeugklasse C mit Anhänger',
|
||||||
D1E: "Fahrzeugklasse D1 mit Anhänger",
|
D1E: 'Fahrzeugklasse D1 mit Anhänger',
|
||||||
DE: "Fahrzeugklasse D mit Anhänger",
|
DE: 'Fahrzeugklasse D mit Anhänger',
|
||||||
L: "Land-, Forstwirtschaftsfahrzeuge, Stapler max 40km/h",
|
L: 'Land-, Forstwirtschaftsfahrzeuge, Stapler max 40km/h',
|
||||||
T: "Land-, Forstwirtschaftsfahrzeuge, Stapler max 60km/h",
|
T: 'Land-, Forstwirtschaftsfahrzeuge, Stapler max 60km/h'
|
||||||
},
|
},
|
||||||
users: "Mitglieder",
|
users: 'Mitglieder',
|
||||||
user: {
|
user: {
|
||||||
login: "Nutzer Anmeldung",
|
login: 'Nutzer Anmeldung',
|
||||||
edit: "Nutzer bearbeiten",
|
edit: 'Nutzer bearbeiten',
|
||||||
user: "Nutzer",
|
user: 'Nutzer',
|
||||||
management: "Mitgliederverwaltung",
|
management: 'Mitgliederverwaltung',
|
||||||
id: "Mitgliedsnr",
|
id: 'Mitgliedsnr',
|
||||||
name: "Name",
|
name: 'Name',
|
||||||
email: "Email",
|
email: 'Email',
|
||||||
status: "Status",
|
status: 'Status',
|
||||||
role: "Nutzerrolle",
|
role: 'Nutzerrolle'
|
||||||
},
|
},
|
||||||
cancel: "Abbrechen",
|
cancel: 'Abbrechen',
|
||||||
confirm: "Bestätigen",
|
confirm: 'Bestätigen',
|
||||||
actions: "Aktionen",
|
actions: 'Aktionen',
|
||||||
edit: "Bearbeiten",
|
edit: 'Bearbeiten',
|
||||||
delete: "Löschen",
|
delete: 'Löschen',
|
||||||
mandate_date_signed: "Mandatserteilungsdatum",
|
mandate_date_signed: 'Mandatserteilungsdatum',
|
||||||
licence_categories: "Führerscheinklassen",
|
licence_categories: 'Führerscheinklassen',
|
||||||
subscription_model: "Mitgliedschatfsmodell",
|
subscription_model: 'Mitgliedschatfsmodell',
|
||||||
licence: "Führerschein",
|
licence: 'Führerschein',
|
||||||
licence_number: "Führerscheinnummer",
|
licence_number: 'Führerscheinnummer',
|
||||||
issued_date: "Ausgabedatum",
|
issued_date: 'Ausgabedatum',
|
||||||
expiration_date: "Ablaufdatum",
|
expiration_date: 'Ablaufdatum',
|
||||||
country: "Land",
|
country: 'Land',
|
||||||
monthly_fee: "Monatliche Gebühr",
|
monthly_fee: 'Monatliche Gebühr',
|
||||||
hourly_rate: "Stundensatz",
|
hourly_rate: 'Stundensatz',
|
||||||
details: "Details",
|
details: 'Details',
|
||||||
conditions: "Bedingungen",
|
conditions: 'Bedingungen',
|
||||||
unknown: "Unbekannt",
|
unknown: 'Unbekannt',
|
||||||
notes: "Notizen",
|
notes: 'Notizen',
|
||||||
address: "Straße & Hausnummer",
|
address: 'Straße & Hausnummer',
|
||||||
city: "Wohnort",
|
city: 'Wohnort',
|
||||||
zip_code: "PLZ",
|
zip_code: 'PLZ',
|
||||||
forgot_password: "Passwort vergessen?",
|
forgot_password: 'Passwort vergessen?',
|
||||||
password: "Passwort",
|
password: 'Passwort',
|
||||||
password_repeat: "Passwort wiederholen",
|
password_repeat: 'Passwort wiederholen',
|
||||||
email: "Email",
|
email: 'Email',
|
||||||
company: "Firma",
|
company: 'Firma',
|
||||||
login: "Anmeldung",
|
login: 'Anmeldung',
|
||||||
profile: "Profil",
|
profile: 'Profil',
|
||||||
membership: "Mitgliedschaft",
|
membership: 'Mitgliedschaft',
|
||||||
bankaccount: "Kontodaten",
|
bankaccount: 'Kontodaten',
|
||||||
first_name: "Vorname",
|
first_name: 'Vorname',
|
||||||
last_name: "Nachname",
|
last_name: 'Nachname',
|
||||||
name: "Name",
|
name: 'Name',
|
||||||
phone: "Telefonnummer",
|
phone: 'Telefonnummer',
|
||||||
date_of_birth: "Geburtstag",
|
dateofbirth: 'Geburtstag',
|
||||||
status: "Status",
|
status: 'Status',
|
||||||
start: "Beginn",
|
start: 'Beginn',
|
||||||
end: "Ende",
|
end: 'Ende',
|
||||||
parent_member_id: "Hauptmitgliedsnr.",
|
parent_member_id: 'Hauptmitgliedsnr.',
|
||||||
bank_account_holder: "Kontoinhaber",
|
bank_account_holder: 'Kontoinhaber',
|
||||||
bank_name: "Bank",
|
bank_name: 'Bank',
|
||||||
iban: "IBAN",
|
iban: 'IBAN',
|
||||||
bic: "BIC",
|
bic: 'BIC',
|
||||||
mandate_reference: "SEPA Mandat",
|
mandate_reference: 'SEPA Mandat',
|
||||||
subscriptions: "Tarifmodelle",
|
subscriptions: 'Tarifmodelle',
|
||||||
payments: "Zahlungen",
|
payments: 'Zahlungen',
|
||||||
add_new: "Neu",
|
add_new: 'Neu',
|
||||||
included_hours_per_year: "Inkludierte Stunden pro Jahr",
|
included_hours_per_year: 'Inkludierte Stunden pro Jahr',
|
||||||
included_hours_per_month: "Inkludierte Stunden pro Monat",
|
included_hours_per_month: 'Inkludierte Stunden pro Monat',
|
||||||
|
|
||||||
// For payments section
|
// For payments section
|
||||||
payment: {
|
payment: {
|
||||||
id: "Zahlungs-Nr",
|
id: 'Zahlungs-Nr',
|
||||||
amount: "Betrag",
|
amount: 'Betrag',
|
||||||
date: "Datum",
|
date: 'Datum',
|
||||||
status: "Status",
|
status: 'Status'
|
||||||
},
|
},
|
||||||
|
|
||||||
// For subscription statuses
|
// For subscription statuses
|
||||||
subscriptionStatus: {
|
subscriptionStatus: {
|
||||||
pending: "Ausstehend",
|
pending: 'Ausstehend',
|
||||||
completed: "Abgeschlossen",
|
completed: 'Abgeschlossen',
|
||||||
failed: "Fehlgeschlagen",
|
failed: 'Fehlgeschlagen',
|
||||||
cancelled: "Storniert",
|
cancelled: 'Storniert'
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import { quintOut } from "svelte/easing";
|
import { quintOut } from 'svelte/easing';
|
||||||
import { crossfade } from "svelte/transition";
|
import { crossfade } from 'svelte/transition';
|
||||||
|
|
||||||
export const [send, receive] = crossfade({
|
export const [send, receive] = crossfade({
|
||||||
duration: (d) => Math.sqrt(d * 200),
|
duration: (d) => Math.sqrt(d * 200),
|
||||||
@@ -8,7 +8,7 @@ export const [send, receive] = crossfade({
|
|||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
fallback(node, params) {
|
fallback(node, params) {
|
||||||
const style = getComputedStyle(node);
|
const style = getComputedStyle(node);
|
||||||
const transform = style.transform === "none" ? "" : style.transform;
|
const transform = style.transform === 'none' ? '' : style.transform;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
duration: 600,
|
duration: 600,
|
||||||
@@ -16,9 +16,9 @@ export const [send, receive] = crossfade({
|
|||||||
css: (t) => `
|
css: (t) => `
|
||||||
transform: ${transform} scale(${t});
|
transform: ${transform} scale(${t});
|
||||||
opacity: ${t}
|
opacity: ${t}
|
||||||
`,
|
`
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,9 +37,7 @@ export const isValidEmail = (email) => {
|
|||||||
* @param {string} password - The password to validate
|
* @param {string} password - The password to validate
|
||||||
*/
|
*/
|
||||||
export const isValidPasswordStrong = (password) => {
|
export const isValidPasswordStrong = (password) => {
|
||||||
const strongRegex = new RegExp(
|
const strongRegex = new RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*])(?=.{8,})');
|
||||||
"^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*])(?=.{8,})"
|
|
||||||
);
|
|
||||||
|
|
||||||
return strongRegex.test(password.trim());
|
return strongRegex.test(password.trim());
|
||||||
};
|
};
|
||||||
@@ -50,7 +48,7 @@ export const isValidPasswordStrong = (password) => {
|
|||||||
*/
|
*/
|
||||||
export const isValidPasswordMedium = (password) => {
|
export const isValidPasswordMedium = (password) => {
|
||||||
const mediumRegex = new RegExp(
|
const mediumRegex = new RegExp(
|
||||||
"^(((?=.*[a-z])(?=.*[A-Z]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[A-Z])(?=.*[0-9])))(?=.{6,})"
|
'^(((?=.*[a-z])(?=.*[A-Z]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[A-Z])(?=.*[0-9])))(?=.{6,})'
|
||||||
);
|
);
|
||||||
|
|
||||||
return mediumRegex.test(password.trim());
|
return mediumRegex.test(password.trim());
|
||||||
@@ -70,15 +68,15 @@ export function isEmpty(obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function toRFC3339(dateString) {
|
export function toRFC3339(dateString) {
|
||||||
if (!dateString) dateString = "0001-01-01T00:00:00.000Z";
|
if (!dateString) dateString = '0001-01-01T00:00:00.000Z';
|
||||||
const date = new Date(dateString);
|
const date = new Date(dateString);
|
||||||
return date.toISOString();
|
return date.toISOString();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fromRFC3339(dateString) {
|
export function fromRFC3339(dateString) {
|
||||||
if (!dateString) dateString = "0001-01-01T00:00:00.000Z";
|
if (!dateString) dateString = '0001-01-01T00:00:00.000Z';
|
||||||
const date = new Date(dateString);
|
const date = new Date(dateString);
|
||||||
return date.toISOString().split("T")[0];
|
return date.toISOString().split('T')[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -86,8 +84,8 @@ export function fromRFC3339(dateString) {
|
|||||||
* @param {App.Locals.User} user - The user object to format
|
* @param {App.Locals.User} user - The user object to format
|
||||||
*/
|
*/
|
||||||
export function userDatesFromRFC3339(user) {
|
export function userDatesFromRFC3339(user) {
|
||||||
if (user.date_of_birth) {
|
if (user.dateofbirth) {
|
||||||
user.date_of_birth = fromRFC3339(user.date_of_birth);
|
user.dateofbirth = fromRFC3339(user.dateofbirth);
|
||||||
}
|
}
|
||||||
if (user.membership) {
|
if (user.membership) {
|
||||||
if (user.membership.start_date) {
|
if (user.membership.start_date) {
|
||||||
@@ -104,9 +102,7 @@ export function userDatesFromRFC3339(user) {
|
|||||||
user.licence.expiration_date = fromRFC3339(user.licence.expiration_date);
|
user.licence.expiration_date = fromRFC3339(user.licence.expiration_date);
|
||||||
}
|
}
|
||||||
if (user.bank_account && user.bank_account.mandate_date_signed) {
|
if (user.bank_account && user.bank_account.mandate_date_signed) {
|
||||||
user.bank_account.mandate_date_signed = fromRFC3339(
|
user.bank_account.mandate_date_signed = fromRFC3339(user.bank_account.mandate_date_signed);
|
||||||
user.bank_account.mandate_date_signed
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,8 +111,8 @@ export function userDatesFromRFC3339(user) {
|
|||||||
* @param {App.Locals.User} user - The user object to format
|
* @param {App.Locals.User} user - The user object to format
|
||||||
*/
|
*/
|
||||||
export function userDatesToRFC3339(user) {
|
export function userDatesToRFC3339(user) {
|
||||||
if (user.date_of_birth) {
|
if (user.dateofbirth) {
|
||||||
user.date_of_birth = toRFC3339(user.date_of_birth);
|
user.dateofbirth = toRFC3339(user.dateofbirth);
|
||||||
}
|
}
|
||||||
if (user.membership) {
|
if (user.membership) {
|
||||||
if (user.membership.start_date) {
|
if (user.membership.start_date) {
|
||||||
@@ -133,9 +129,7 @@ export function userDatesToRFC3339(user) {
|
|||||||
user.licence.expiration_date = toRFC3339(user.licence.expiration_date);
|
user.licence.expiration_date = toRFC3339(user.licence.expiration_date);
|
||||||
}
|
}
|
||||||
if (user.bank_account && user.bank_account.mandate_date_signed) {
|
if (user.bank_account && user.bank_account.mandate_date_signed) {
|
||||||
user.bank_account.mandate_date_signed = toRFC3339(
|
user.bank_account.mandate_date_signed = toRFC3339(user.bank_account.mandate_date_signed);
|
||||||
user.bank_account.mandate_date_signed
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,13 +140,13 @@ export function userDatesToRFC3339(user) {
|
|||||||
*/
|
*/
|
||||||
export function formatError(obj) {
|
export function formatError(obj) {
|
||||||
const errors = [];
|
const errors = [];
|
||||||
if (typeof obj === "object" && obj !== null) {
|
if (typeof obj === 'object' && obj !== null) {
|
||||||
if (Array.isArray(obj)) {
|
if (Array.isArray(obj)) {
|
||||||
obj.forEach((error) => {
|
obj.forEach((error) => {
|
||||||
errors.push({
|
errors.push({
|
||||||
field: error.field,
|
field: error.field,
|
||||||
key: error.key,
|
key: error.key,
|
||||||
id: Math.random() * 1000,
|
id: Math.random() * 1000
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -160,15 +154,15 @@ export function formatError(obj) {
|
|||||||
errors.push({
|
errors.push({
|
||||||
field: field,
|
field: field,
|
||||||
key: obj[field].key,
|
key: obj[field].key,
|
||||||
id: Math.random() * 1000,
|
id: Math.random() * 1000
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
errors.push({
|
errors.push({
|
||||||
field: "general",
|
field: 'general',
|
||||||
key: obj,
|
key: obj,
|
||||||
id: 0,
|
id: 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return errors;
|
return errors;
|
||||||
@@ -184,20 +178,20 @@ export function refreshCookie(newToken, event) {
|
|||||||
const match = newToken.match(/jwt=([^;]+)/);
|
const match = newToken.match(/jwt=([^;]+)/);
|
||||||
if (match) {
|
if (match) {
|
||||||
if (event) {
|
if (event) {
|
||||||
event.cookies.set("jwt", match[1], {
|
event.cookies.set('jwt', match[1], {
|
||||||
path: "/",
|
path: '/',
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: process.env.NODE_ENV === "production", // Secure in production
|
secure: process.env.NODE_ENV === 'production', // Secure in production
|
||||||
sameSite: "lax",
|
sameSite: 'lax',
|
||||||
maxAge: 5 * 24 * 60 * 60, // 5 days in seconds
|
maxAge: 5 * 24 * 60 * 60 // 5 days in seconds
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
cookies.set("jwt", match[1], {
|
cookies.set('jwt', match[1], {
|
||||||
path: "/",
|
path: '/',
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: process.env.NODE_ENV === "production", // Secure in production
|
secure: process.env.NODE_ENV === 'production', // Secure in production
|
||||||
sameSite: "lax",
|
sameSite: 'lax',
|
||||||
maxAge: 5 * 24 * 60 * 60, // 5 days in seconds
|
maxAge: 5 * 24 * 60 * 60 // 5 days in seconds
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
121
frontend/src/lib/utils/processing.js
Normal file
121
frontend/src/lib/utils/processing.js
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
import { toRFC3339 } from './helpers';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts FormData to a nested object structure
|
||||||
|
* @param {FormData} formData - The FormData object to convert
|
||||||
|
* @returns {{ user: Partial<App.Locals['user']> }} Nested object representation of the form data
|
||||||
|
*/
|
||||||
|
export function formDataToObject(formData) {
|
||||||
|
/** @type { Partial<App.Locals['user']> } */
|
||||||
|
const object = {};
|
||||||
|
|
||||||
|
console.log('Form data entries:');
|
||||||
|
for (const [key, value] of formData.entries()) {
|
||||||
|
console.log('Key:', key, 'Value:', value);
|
||||||
|
}
|
||||||
|
for (const [key, value] of formData.entries()) {
|
||||||
|
/** @type {string[]} */
|
||||||
|
const keys = key.match(/\[([^\]]+)\]/g)?.map((k) => k.slice(1, -1)) || [key];
|
||||||
|
console.log('Processed keys:', keys);
|
||||||
|
/** @type {Record<string, any>} */
|
||||||
|
let current = object;
|
||||||
|
|
||||||
|
console.log('Current object state:', JSON.stringify(current));
|
||||||
|
for (let i = 0; i < keys.length - 1; i++) {
|
||||||
|
/**
|
||||||
|
* Create nested object if it doesn't exist
|
||||||
|
* @type {Record<string, any>}
|
||||||
|
* @description Ensures proper nesting structure for user data fields
|
||||||
|
* @example
|
||||||
|
* // For input name="user[membership][status]"
|
||||||
|
* // Creates: { user: { membership: { status: value } } }
|
||||||
|
*/
|
||||||
|
current[keys[i]] = current[keys[i]] || {};
|
||||||
|
/**
|
||||||
|
* Move to the next level of the object
|
||||||
|
* @type {Record<string, any>}
|
||||||
|
*/
|
||||||
|
current = current[keys[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastKey = keys[keys.length - 1];
|
||||||
|
if (lastKey.endsWith('[]')) {
|
||||||
|
/**
|
||||||
|
* Handle array fields (licence categories)
|
||||||
|
*/
|
||||||
|
const arrayKey = lastKey.slice(0, -2);
|
||||||
|
current[arrayKey] = current[arrayKey] || [];
|
||||||
|
current[arrayKey].push(value);
|
||||||
|
} else {
|
||||||
|
current[lastKey] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { user: object };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes the raw form data into the expected user data structure
|
||||||
|
* @param {{ user: Partial<App.Locals['user']> } } rawData - The raw form data object
|
||||||
|
* @returns {{ user: Partial<App.Locals['user']> }} Processed user data
|
||||||
|
*/
|
||||||
|
export function processFormData(rawData) {
|
||||||
|
/** @type {{ user: Partial<App.Locals['user']> }} */
|
||||||
|
const processedData = {
|
||||||
|
user: {
|
||||||
|
id: Number(rawData.user.id) || 0,
|
||||||
|
status: Number(rawData.user.status),
|
||||||
|
role_id: Number(rawData.user.role_id),
|
||||||
|
first_name: String(rawData.user.first_name),
|
||||||
|
last_name: String(rawData.user.last_name),
|
||||||
|
email: String(rawData.user.email),
|
||||||
|
phone: String(rawData.user.phone || ''),
|
||||||
|
company: String(rawData.user.company || ''),
|
||||||
|
dateofbirth: toRFC3339(rawData.user.dateofbirth),
|
||||||
|
address: String(rawData.user.address || ''),
|
||||||
|
zip_code: String(rawData.user.zip_code || ''),
|
||||||
|
city: String(rawData.user.city || ''),
|
||||||
|
notes: String(rawData.user.notes || ''),
|
||||||
|
profile_picture: String(rawData.user.profile_picture || ''),
|
||||||
|
|
||||||
|
membership: {
|
||||||
|
id: Number(rawData.user.membership?.id) || 0,
|
||||||
|
status: Number(rawData.user.membership?.status),
|
||||||
|
start_date: toRFC3339(rawData.user.membership?.start_date),
|
||||||
|
end_date: toRFC3339(rawData.user.membership?.end_date),
|
||||||
|
parent_member_id: Number(rawData.user.membership?.parent_member_id) || 0,
|
||||||
|
subscription_model: {
|
||||||
|
id: Number(rawData.user.membership?.subscription_model?.id) || 0,
|
||||||
|
name: String(rawData.user.membership?.subscription_model?.name) || ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
licence: {
|
||||||
|
id: Number(rawData.user.licence?.id) || 0,
|
||||||
|
status: Number(rawData.user.licence?.status),
|
||||||
|
licence_number: String(rawData.user.licence?.licence_number || ''),
|
||||||
|
issued_date: toRFC3339(rawData.user.licence?.issued_date),
|
||||||
|
expiration_date: toRFC3339(rawData.user.licence?.expiration_date),
|
||||||
|
country: String(rawData.user.licence?.country || ''),
|
||||||
|
licence_categories: rawData.user.licence?.licence_categories || []
|
||||||
|
},
|
||||||
|
|
||||||
|
bank_account: {
|
||||||
|
id: Number(rawData.user.bank_account?.id) || 0,
|
||||||
|
account_holder_name: String(rawData.user.bank_account?.account_holder_name || ''),
|
||||||
|
bank: String(rawData.user.bank_account?.bank || ''),
|
||||||
|
iban: String(rawData.user.bank_account?.iban || ''),
|
||||||
|
bic: String(rawData.user.bank_account?.bic || ''),
|
||||||
|
mandate_reference: String(rawData.user.bank_account?.mandate_reference || ''),
|
||||||
|
mandate_date_signed: toRFC3339(rawData.user.bank_account?.mandate_date_signed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove undefined or null properties
|
||||||
|
const cleanUpdateData = JSON.parse(JSON.stringify(processedData), (key, value) =>
|
||||||
|
value !== null && value !== '' ? value : undefined
|
||||||
|
);
|
||||||
|
console.dir(cleanUpdateData);
|
||||||
|
return cleanUpdateData;
|
||||||
|
}
|
||||||
@@ -1,11 +1,7 @@
|
|||||||
import { BASE_API_URI } from "$lib/utils/constants";
|
import { BASE_API_URI } from '$lib/utils/constants';
|
||||||
import {
|
import { formatError, userDatesFromRFC3339 } from '$lib/utils/helpers';
|
||||||
formatError,
|
import { fail, redirect } from '@sveltejs/kit';
|
||||||
userDatesFromRFC3339,
|
import { formDataToObject, processFormData } from '$lib/utils/processing';
|
||||||
userDatesToRFC3339,
|
|
||||||
} from "$lib/utils/helpers";
|
|
||||||
import { fail, redirect } from "@sveltejs/kit";
|
|
||||||
import { toRFC3339 } from "$lib/utils/helpers";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} UpdateData
|
* @typedef {Object} UpdateData
|
||||||
@@ -33,87 +29,24 @@ export const actions = {
|
|||||||
updateUser: async ({ request, fetch, cookies, locals }) => {
|
updateUser: async ({ request, fetch, cookies, locals }) => {
|
||||||
let formData = await request.formData();
|
let formData = await request.formData();
|
||||||
|
|
||||||
/** @type {App.Types['licenceCategory'][]} */
|
const rawData = formDataToObject(formData);
|
||||||
const licenceCategories = formData
|
const processedData = processFormData(rawData);
|
||||||
.getAll("licence_categories[]")
|
|
||||||
.filter((value) => typeof value === "string")
|
|
||||||
.map((value) => {
|
|
||||||
try {
|
|
||||||
return JSON.parse(value);
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Failed to parse licence category:", value);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/** @type {Partial<App.Locals['user']>} */
|
|
||||||
const userData = {
|
|
||||||
id: Number(formData.get("id")),
|
|
||||||
first_name: String(formData.get("first_name")),
|
|
||||||
last_name: String(formData.get("last_name")),
|
|
||||||
email: String(formData.get("email")),
|
|
||||||
phone: String(formData.get("phone")),
|
|
||||||
notes: String(formData.get("notes")),
|
|
||||||
address: String(formData.get("address")),
|
|
||||||
zip_code: String(formData.get("zip_code")),
|
|
||||||
city: String(formData.get("city")),
|
|
||||||
date_of_birth: toRFC3339(formData.get("date_of_birth")),
|
|
||||||
company: String(formData.get("company")),
|
|
||||||
profile_picture: String(formData.get("profile_picture")),
|
|
||||||
membership: {
|
|
||||||
id: Number(formData.get("membership_id")),
|
|
||||||
start_date: toRFC3339(formData.get("membership_start_date")),
|
|
||||||
end_date: toRFC3339(formData.get("membership_end_date")),
|
|
||||||
status: Number(formData.get("membership_status")),
|
|
||||||
parent_member_id: Number(formData.get("parent_member_id")),
|
|
||||||
subscription_model: {
|
|
||||||
id: Number(formData.get("subscription_model_id")),
|
|
||||||
name: String(formData.get("subscription_model_name")),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
bank_account: {
|
|
||||||
id: Number(formData.get("bank_account_id")),
|
|
||||||
mandate_date_signed: toRFC3339(formData.get("mandate_date_signed")),
|
|
||||||
bank: String(formData.get("bank")),
|
|
||||||
account_holder_name: String(formData.get("account_holder_name")),
|
|
||||||
iban: String(formData.get("iban")),
|
|
||||||
bic: String(formData.get("bic")),
|
|
||||||
mandate_reference: String(formData.get("mandate_reference")),
|
|
||||||
},
|
|
||||||
licence: {
|
|
||||||
id: Number(formData.get("drivers_licence_id")),
|
|
||||||
status: Number(formData.get("licence_status")),
|
|
||||||
licence_number: String(formData.get("licence_number")),
|
|
||||||
issued_date: toRFC3339(formData.get("issued_date")),
|
|
||||||
expiration_date: toRFC3339(formData.get("expiration_date")),
|
|
||||||
country: String(formData.get("country")),
|
|
||||||
licence_categories: licenceCategories,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// userDatesToRFC3339(userData);
|
|
||||||
|
|
||||||
/** @type {UpdateData} */
|
|
||||||
const updateData = { user: userData };
|
|
||||||
// Remove undefined or null properties
|
|
||||||
const cleanUpdateData = JSON.parse(
|
|
||||||
JSON.stringify(updateData),
|
|
||||||
(key, value) => (value !== null && value !== "" ? value : undefined)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
console.dir(processedData.user.membership);
|
||||||
|
const isCreating = !processedData.user.id || processedData.user.id === 0;
|
||||||
|
console.log('Is updating: ', isCreating);
|
||||||
console.dir(formData);
|
console.dir(formData);
|
||||||
console.dir(cleanUpdateData);
|
|
||||||
const apiURL = `${BASE_API_URI}/backend/users/update/`;
|
const apiURL = `${BASE_API_URI}/backend/users/update/`;
|
||||||
|
|
||||||
/** @type {RequestInit} */
|
/** @type {RequestInit} */
|
||||||
const requestUpdateOptions = {
|
const requestUpdateOptions = {
|
||||||
method: "PATCH",
|
method: 'PATCH',
|
||||||
credentials: "include",
|
credentials: 'include',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
Cookie: `jwt=${cookies.get("jwt")}`,
|
Cookie: `jwt=${cookies.get('jwt')}`
|
||||||
},
|
},
|
||||||
body: JSON.stringify(cleanUpdateData),
|
body: JSON.stringify(processedData)
|
||||||
};
|
};
|
||||||
const res = await fetch(apiURL, requestUpdateOptions);
|
const res = await fetch(apiURL, requestUpdateOptions);
|
||||||
|
|
||||||
@@ -128,6 +61,7 @@ export const actions = {
|
|||||||
userDatesFromRFC3339(locals.user);
|
userDatesFromRFC3339(locals.user);
|
||||||
throw redirect(303, `/auth/about/${response.id}`);
|
throw redirect(303, `/auth/about/${response.id}`);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param request - The request object
|
* @param request - The request object
|
||||||
@@ -141,11 +75,11 @@ export const actions = {
|
|||||||
|
|
||||||
/** @type {RequestInit} */
|
/** @type {RequestInit} */
|
||||||
const requestInitOptions = {
|
const requestInitOptions = {
|
||||||
method: "POST",
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Cookie: `jwt=${cookies.get("jwt")}`,
|
Cookie: `jwt=${cookies.get('jwt')}`
|
||||||
},
|
},
|
||||||
body: formData,
|
body: formData
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await fetch(`${BASE_API_URI}/file/upload/`, requestInitOptions);
|
const res = await fetch(`${BASE_API_URI}/file/upload/`, requestInitOptions);
|
||||||
@@ -160,7 +94,7 @@ export const actions = {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
profile_picture: response[""],
|
profile_picture: response['']
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -177,11 +111,11 @@ export const actions = {
|
|||||||
|
|
||||||
/** @type {RequestInit} */
|
/** @type {RequestInit} */
|
||||||
const requestInitOptions = {
|
const requestInitOptions = {
|
||||||
method: "DELETE",
|
method: 'DELETE',
|
||||||
headers: {
|
headers: {
|
||||||
Cookie: `jwt=${cookies.get("jwt")}`,
|
Cookie: `jwt=${cookies.get('jwt')}`
|
||||||
},
|
},
|
||||||
body: formData,
|
body: formData
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await fetch(`${BASE_API_URI}/file/delete/`, requestInitOptions);
|
const res = await fetch(`${BASE_API_URI}/file/delete/`, requestInitOptions);
|
||||||
@@ -194,7 +128,7 @@ export const actions = {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
profile_picture: "",
|
profile_picture: ''
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -65,10 +65,10 @@
|
|||||||
<span class="value">{user.phone}</span>
|
<span class="value">{user.phone}</span>
|
||||||
</h3>
|
</h3>
|
||||||
{/if}
|
{/if}
|
||||||
{#if user.date_of_birth}
|
{#if user.dateofbirth}
|
||||||
<h3 class="hero-subtitle subtitle info-row">
|
<h3 class="hero-subtitle subtitle info-row">
|
||||||
<span class="label">Geburtstag:</span>
|
<span class="label">Geburtstag:</span>
|
||||||
<span class="value">{user.date_of_birth}</span>
|
<span class="value">{user.dateofbirth}</span>
|
||||||
</h3>
|
</h3>
|
||||||
{/if}
|
{/if}
|
||||||
{#if user.notes}
|
{#if user.notes}
|
||||||
|
|||||||
@@ -2,134 +2,10 @@
|
|||||||
// - Implement a load function to fetch a list of all users.
|
// - Implement a load function to fetch a list of all users.
|
||||||
// - Create actions for updating user information (similar to the about/[id] route).
|
// - Create actions for updating user information (similar to the about/[id] route).
|
||||||
|
|
||||||
import { BASE_API_URI } from "$lib/utils/constants";
|
import { BASE_API_URI } from '$lib/utils/constants';
|
||||||
import { formatError, userDatesFromRFC3339 } from "$lib/utils/helpers";
|
import { formatError, userDatesFromRFC3339 } from '$lib/utils/helpers';
|
||||||
import { fail, redirect } from "@sveltejs/kit";
|
import { fail, redirect } from '@sveltejs/kit';
|
||||||
import { toRFC3339 } from "$lib/utils/helpers";
|
import { formDataToObject, processFormData } from '$lib/utils/processing';
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts FormData to a nested object structure
|
|
||||||
* @param {FormData} formData - The FormData object to convert
|
|
||||||
* @returns {{ user: Partial<App.Locals['user']> }} Nested object representation of the form data
|
|
||||||
*/
|
|
||||||
function formDataToObject(formData) {
|
|
||||||
/** @type { Partial<App.Locals['user']> } */
|
|
||||||
const object = {};
|
|
||||||
|
|
||||||
console.log("Form data entries:");
|
|
||||||
for (const [key, value] of formData.entries()) {
|
|
||||||
console.log("Key:", key, "Value:", value);
|
|
||||||
}
|
|
||||||
for (const [key, value] of formData.entries()) {
|
|
||||||
/** @type {string[]} */
|
|
||||||
const keys = key.match(/\[([^\]]+)\]/g)?.map((k) => k.slice(1, -1)) || [
|
|
||||||
key,
|
|
||||||
];
|
|
||||||
console.log("Processed keys:", keys);
|
|
||||||
/** @type {Record<string, any>} */
|
|
||||||
let current = object;
|
|
||||||
|
|
||||||
console.log("Current object state:", JSON.stringify(current));
|
|
||||||
for (let i = 0; i < keys.length - 1; i++) {
|
|
||||||
/**
|
|
||||||
* Create nested object if it doesn't exist
|
|
||||||
* @type {Record<string, any>}
|
|
||||||
* @description Ensures proper nesting structure for user data fields
|
|
||||||
* @example
|
|
||||||
* // For input name="user[membership][status]"
|
|
||||||
* // Creates: { user: { membership: { status: value } } }
|
|
||||||
*/
|
|
||||||
current[keys[i]] = current[keys[i]] || {};
|
|
||||||
/**
|
|
||||||
* Move to the next level of the object
|
|
||||||
* @type {Record<string, any>}
|
|
||||||
*/
|
|
||||||
current = current[keys[i]];
|
|
||||||
}
|
|
||||||
|
|
||||||
const lastKey = keys[keys.length - 1];
|
|
||||||
if (lastKey.endsWith("[]")) {
|
|
||||||
/**
|
|
||||||
* Handle array fields (licence categories)
|
|
||||||
*/
|
|
||||||
const arrayKey = lastKey.slice(0, -2);
|
|
||||||
current[arrayKey] = current[arrayKey] || [];
|
|
||||||
current[arrayKey].push(value);
|
|
||||||
} else {
|
|
||||||
current[lastKey] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { user: object };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes the raw form data into the expected user data structure
|
|
||||||
* @param {{ user: Partial<App.Locals['user']> } } rawData - The raw form data object
|
|
||||||
* @returns {{ user: Partial<App.Locals['user']> }} Processed user data
|
|
||||||
*/
|
|
||||||
function processFormData(rawData) {
|
|
||||||
/** @type {{ user: Partial<App.Locals['user']> }} */
|
|
||||||
const processedData = {
|
|
||||||
user: {
|
|
||||||
id: Number(rawData.user.id) || 0,
|
|
||||||
status: Number(rawData.user.status),
|
|
||||||
role_id: Number(rawData.user.role_id),
|
|
||||||
first_name: String(rawData.user.first_name),
|
|
||||||
last_name: String(rawData.user.last_name),
|
|
||||||
email: String(rawData.user.email),
|
|
||||||
phone: String(rawData.user.phone || ""),
|
|
||||||
company: String(rawData.user.company || ""),
|
|
||||||
date_of_birth: toRFC3339(rawData.user.date_of_birth),
|
|
||||||
address: String(rawData.user.address || ""),
|
|
||||||
zip_code: String(rawData.user.zip_code || ""),
|
|
||||||
city: String(rawData.user.city || ""),
|
|
||||||
notes: String(rawData.user.notes || ""),
|
|
||||||
profile_picture: String(rawData.user.profile_picture || ""),
|
|
||||||
|
|
||||||
membership: {
|
|
||||||
id: Number(rawData.user.membership?.id) || 0,
|
|
||||||
status: Number(rawData.user.membership?.status),
|
|
||||||
start_date: toRFC3339(rawData.user.membership?.start_date),
|
|
||||||
end_date: toRFC3339(rawData.user.membership?.end_date),
|
|
||||||
parent_member_id:
|
|
||||||
Number(rawData.user.membership?.parent_member_id) || 0,
|
|
||||||
subscription_model: {
|
|
||||||
id: Number(rawData.user.membership?.subscription_model?.id) || 0,
|
|
||||||
name: String(rawData.user.membership?.subscription_model?.name) || "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
licence: {
|
|
||||||
id: Number(rawData.user.licence?.id) || 0,
|
|
||||||
status: Number(rawData.user.licence?.status),
|
|
||||||
licence_number: String(rawData.user.licence?.licence_number || ""),
|
|
||||||
issued_date: toRFC3339(rawData.user.licence?.issued_date),
|
|
||||||
expiration_date: toRFC3339(rawData.user.licence?.expiration_date),
|
|
||||||
country: String(rawData.user.licence?.country || ""),
|
|
||||||
licence_categories: rawData.user.licence?.licence_categories || [],
|
|
||||||
},
|
|
||||||
|
|
||||||
bank_account: {
|
|
||||||
id: Number(rawData.user.bank_account?.id) || 0,
|
|
||||||
account_holder_name: String(
|
|
||||||
rawData.user.bank_account?.account_holder_name || ""
|
|
||||||
),
|
|
||||||
bank: String(rawData.user.bank_account?.bank || ""),
|
|
||||||
iban: String(rawData.user.bank_account?.iban || ""),
|
|
||||||
bic: String(rawData.user.bank_account?.bic || ""),
|
|
||||||
mandate_reference: String(
|
|
||||||
rawData.user.bank_account?.mandate_reference || ""
|
|
||||||
),
|
|
||||||
mandate_date_signed: toRFC3339(
|
|
||||||
rawData.user.bank_account?.mandate_date_signed
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return processedData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @type {import('./$types').PageServerLoad} */
|
/** @type {import('./$types').PageServerLoad} */
|
||||||
export async function load({ locals, params }) {
|
export async function load({ locals, params }) {
|
||||||
@@ -152,30 +28,23 @@ export const actions = {
|
|||||||
updateUser: async ({ request, fetch, cookies, locals }) => {
|
updateUser: async ({ request, fetch, cookies, locals }) => {
|
||||||
let formData = await request.formData();
|
let formData = await request.formData();
|
||||||
|
|
||||||
// Convert form data to nested object
|
|
||||||
const rawData = formDataToObject(formData);
|
const rawData = formDataToObject(formData);
|
||||||
|
|
||||||
const processedData = processFormData(rawData);
|
const processedData = processFormData(rawData);
|
||||||
|
|
||||||
// Remove undefined or null properties
|
|
||||||
const cleanUpdateData = JSON.parse(
|
|
||||||
JSON.stringify(processedData),
|
|
||||||
(key, value) => (value !== null && value !== "" ? value : undefined)
|
|
||||||
);
|
|
||||||
console.dir(processedData.user.membership);
|
console.dir(processedData.user.membership);
|
||||||
const isCreating = !processedData.user.id || processedData.user.id === 0;
|
const isCreating = !processedData.user.id || processedData.user.id === 0;
|
||||||
console.log("Is creating: ", isCreating);
|
console.log('Is creating: ', isCreating);
|
||||||
const apiURL = `${BASE_API_URI}/backend/users/update`;
|
const apiURL = `${BASE_API_URI}/backend/users/update`;
|
||||||
|
|
||||||
/** @type {RequestInit} */
|
/** @type {RequestInit} */
|
||||||
const requestOptions = {
|
const requestOptions = {
|
||||||
method: isCreating ? "POST" : "PATCH",
|
method: isCreating ? 'POST' : 'PATCH',
|
||||||
credentials: "include",
|
credentials: 'include',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
Cookie: `jwt=${cookies.get("jwt")}`,
|
Cookie: `jwt=${cookies.get('jwt')}`
|
||||||
},
|
},
|
||||||
body: JSON.stringify(cleanUpdateData),
|
body: JSON.stringify(processedData)
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await fetch(apiURL, requestOptions);
|
const res = await fetch(apiURL, requestOptions);
|
||||||
@@ -187,9 +56,9 @@ export const actions = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const response = await res.json();
|
const response = await res.json();
|
||||||
console.log("Server success response:", response);
|
console.log('Server success response:', response);
|
||||||
locals.user = response;
|
locals.user = response;
|
||||||
userDatesFromRFC3339(locals.user);
|
userDatesFromRFC3339(locals.user);
|
||||||
throw redirect(303, `/auth/about/${response.id}`);
|
throw redirect(303, `/auth/about/${response.id}`);
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -58,8 +58,8 @@
|
|||||||
on:click={() => setActiveSection('users')}
|
on:click={() => setActiveSection('users')}
|
||||||
>
|
>
|
||||||
<i class="fas fa-users"></i>
|
<i class="fas fa-users"></i>
|
||||||
<span class="nav-badge">{users.length}</span>
|
|
||||||
{$t('users')}
|
{$t('users')}
|
||||||
|
<span class="nav-badge">{users.length}</span>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
@@ -68,8 +68,8 @@
|
|||||||
on:click={() => setActiveSection('subscriptions')}
|
on:click={() => setActiveSection('subscriptions')}
|
||||||
>
|
>
|
||||||
<i class="fas fa-clipboard-list"></i>
|
<i class="fas fa-clipboard-list"></i>
|
||||||
<span class="nav-badge">{subscriptions.length}</span>
|
|
||||||
{$t('subscriptions')}
|
{$t('subscriptions')}
|
||||||
|
<span class="nav-badge">{subscriptions.length}</span>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
@@ -238,7 +238,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
color: white;
|
color: var(--text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout {
|
.layout {
|
||||||
@@ -252,8 +252,8 @@
|
|||||||
.sidebar {
|
.sidebar {
|
||||||
width: 250px;
|
width: 250px;
|
||||||
min-height: 600px;
|
min-height: 600px;
|
||||||
background: #2f2f2f;
|
background: var(--surface0);
|
||||||
border-right: 1px solid #494848;
|
border-right: 1px solid var(--surface1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-list {
|
.nav-list {
|
||||||
@@ -272,7 +272,7 @@
|
|||||||
background: none;
|
background: none;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #9b9b9b;
|
color: var(--subtext0);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
letter-spacing: 1px;
|
letter-spacing: 1px;
|
||||||
@@ -280,12 +280,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.nav-link:hover {
|
.nav-link:hover {
|
||||||
background: #fdfff5;
|
background: var(--surface1);
|
||||||
|
color: var(--text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-link.active {
|
.nav-link.active {
|
||||||
background: #494848;
|
background: var(--surface2);
|
||||||
color: white;
|
color: var(--lavender);
|
||||||
|
border-left: 3px solid var(--mauve);
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-content {
|
.main-content {
|
||||||
@@ -295,20 +297,29 @@
|
|||||||
|
|
||||||
.accordion-item {
|
.accordion-item {
|
||||||
border: none;
|
border: none;
|
||||||
background: #2f2f2f;
|
background: var(--surface0);
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.accordion-header {
|
.accordion-header {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-family: 'Roboto Mono', monospace;
|
font-family: 'Roboto Mono', monospace;
|
||||||
color: white;
|
color: var(--text);
|
||||||
|
background: var(--surface1);
|
||||||
|
transition: background-color 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accordion-header:hover {
|
||||||
|
background: var(--surface2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.accordion-content {
|
.accordion-content {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
background: #494848;
|
background: var(--surface0);
|
||||||
|
border-top: 1px solid var(--surface1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.table {
|
.table {
|
||||||
@@ -325,11 +336,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.table th {
|
.table th {
|
||||||
color: #9b9b9b;
|
color: var(--subtext1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.table td {
|
.table td {
|
||||||
color: white;
|
color: var(--text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 680px) {
|
@media (max-width: 680px) {
|
||||||
@@ -358,5 +369,42 @@
|
|||||||
|
|
||||||
.section-header h2 {
|
.section-header h2 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
color: var(--lavender);
|
||||||
|
}
|
||||||
|
/* Additional styles for better visual hierarchy */
|
||||||
|
details[open] .accordion-header {
|
||||||
|
background: var(--surface2);
|
||||||
|
color: var(--lavender);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-group {
|
||||||
|
margin-top: 1rem;
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Style for the nav badge */
|
||||||
|
.nav-badge {
|
||||||
|
background: var(--surface2);
|
||||||
|
color: var(--text);
|
||||||
|
padding: 0.2rem 0.5rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Improved focus states */
|
||||||
|
.nav-link:focus,
|
||||||
|
.accordion-header:focus {
|
||||||
|
outline: 2px solid var(--mauve);
|
||||||
|
outline-offset: -2px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add subtle transitions */
|
||||||
|
.accordion-item,
|
||||||
|
.accordion-header,
|
||||||
|
.nav-link {
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type User struct {
|
|||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
DeletedAt *time.Time `gorm:"index"`
|
DeletedAt *time.Time `gorm:"index"`
|
||||||
DateOfBirth time.Time `gorm:"not null" json:"date_of_birth" binding:"required,safe_content"`
|
DateOfBirth time.Time `gorm:"not null" json:"dateofbirth" binding:"required,safe_content"`
|
||||||
Company string `json:"company" binding:"omitempty,omitnil,safe_content"`
|
Company string `json:"company" binding:"omitempty,omitnil,safe_content"`
|
||||||
Phone string `json:"phone" binding:"omitempty,omitnil,safe_content"`
|
Phone string `json:"phone" binding:"omitempty,omitnil,safe_content"`
|
||||||
Notes string `json:"notes" binding:"safe_content"`
|
Notes string `json:"notes" binding:"safe_content"`
|
||||||
@@ -75,7 +75,7 @@ func (u *User) Safe() map[string]interface{} {
|
|||||||
"id": u.ID,
|
"id": u.ID,
|
||||||
"role_id": u.RoleID,
|
"role_id": u.RoleID,
|
||||||
"company": u.Company,
|
"company": u.Company,
|
||||||
"date_of_birth": u.DateOfBirth,
|
"dateofbirth": u.DateOfBirth,
|
||||||
"membership": map[string]interface{}{
|
"membership": map[string]interface{}{
|
||||||
"id": u.Membership.ID,
|
"id": u.Membership.ID,
|
||||||
"start_date": u.Membership.StartDate,
|
"start_date": u.Membership.StartDate,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ func validateUser(sl validator.StructLevel) {
|
|||||||
}
|
}
|
||||||
// Validate User > 18 years old
|
// Validate User > 18 years old
|
||||||
if !isSuper && user.DateOfBirth.After(time.Now().AddDate(-18, 0, 0)) {
|
if !isSuper && user.DateOfBirth.After(time.Now().AddDate(-18, 0, 0)) {
|
||||||
sl.ReportError(user.DateOfBirth, "DateOfBirth", "date_of_birth", "age", "")
|
sl.ReportError(user.DateOfBirth, "DateOfBirth", "dateofbirth", "age", "")
|
||||||
}
|
}
|
||||||
// validate subscriptionModel
|
// validate subscriptionModel
|
||||||
logger.Error.Printf("User: %#v", user)
|
logger.Error.Printf("User: %#v", user)
|
||||||
|
|||||||
Reference in New Issue
Block a user