Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 40 additions & 21 deletions apps/web/src/app/data/services/account.service.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,11 @@
import { Injectable, signal, WritableSignal, inject } from '@angular/core';
import { ApiService } from '../../core/services/api.service';
import { Account, LoginLink } from '@zoneless/shared-types';
import { CreateAccountInput } from '@zoneless/shared-schemas';

/**
* Input type for updating an account.
* All fields are optional - only provided fields will be updated.
* Protected fields (id, object, created, payouts_enabled, details_submitted, tos_acceptance)
* cannot be updated directly.
*/
export type AccountUpdateInput = Partial<
Omit<
Account,
| 'id'
| 'object'
| 'created'
| 'payouts_enabled'
| 'details_submitted'
| 'tos_acceptance'
| 'individual'
>
>;
import {
CreateAccountInput,
UpdateAccountInput,
} from '@zoneless/shared-schemas';
import { SettingsCardRow } from '../../shared';

@Injectable({
providedIn: 'root',
Expand Down Expand Up @@ -59,7 +44,7 @@ export class AccountService {

async UpdateAccount(
accountId: string,
data: AccountUpdateInput
data: UpdateAccountInput
): Promise<Account> {
this.loading.set(true);
try {
Expand Down Expand Up @@ -162,4 +147,38 @@ export class AccountService {

return account.email ?? individual?.email ?? account.id;
}

/**
* Display title for the Business details settings card.
*/
GetBusinessDetailsTitle(account: Account | null): string {
if (!account) return 'Business details';
return (
account.business_profile?.name?.trim() ||
account.settings?.dashboard?.display_name?.trim() ||
'Business details'
);
}

GetBusinessDetailsCardRows(account: Account | null): SettingsCardRow[] {
if (!account) return [];

return [
{
label: 'Logo',
value: account.settings?.branding?.logo || '—',
type: 'text',
},
{
label: 'Terms of Service',
value: account.settings?.terms_url || '—',
type: 'text',
},
{
label: 'Privacy Policy',
value: account.settings?.privacy_url || '—',
type: 'text',
},
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,21 @@
<h1>Settings</h1>
</div>

<!-- Personal Details Card -->
<!-- Business Details Card (platform only) -->
@if (authService.isPlatform()) {
<div class="view-section">
<div class="settings-section-title">Business details</div>
<app-settings-card
[title]="accountService.GetBusinessDetailsTitle(accountService.account())"
[rows]="accountService.GetBusinessDetailsCardRows(accountService.account())"
[showEditButton]="true"
(editClicked)="OnEditBusinessClick()"
></app-settings-card>
</div>
}

<!-- Personal Details Card (connected accounts only) -->
@if (!authService.isPlatform()) {
<div class="view-section">
<div class="settings-section-title">Personal details</div>
<app-settings-card
Expand All @@ -12,6 +26,7 @@ <h1>Settings</h1>
(editClicked)="OnEditPersonClick()"
></app-settings-card>
</div>
}

<!-- External Wallet Card -->
@if (externalWalletService.wallet()) {
Expand All @@ -37,7 +52,29 @@ <h1>Settings</h1>
</button>
</div>

<!-- Edit Business Details Slide Panel -->
@if (authService.isPlatform()) {
<app-slide-panel
[isOpen]="editBusinessPanelOpen()"
title="Edit business details"
[loading]="editBusinessLoading()"
submitLabel="Save"
[submitDisabled]="false"
(closed)="OnEditBusinessPanelClosed()"
(submitted)="OnEditBusinessSubmit()"
>
<app-business-profile-form
#editBusinessForm
mode="edit"
[account]="accountService.account()"
[isOpen]="editBusinessPanelOpen()"
[showErrors]="editBusinessShowErrors()"
></app-business-profile-form>
</app-slide-panel>
}

<!-- Edit Person Slide Panel -->
@if (!authService.isPlatform()) {
<app-slide-panel
[isOpen]="editPersonPanelOpen()"
title="Edit personal details"
Expand All @@ -55,6 +92,7 @@ <h1>Settings</h1>
[showErrors]="editPersonShowErrors()"
></app-person-form>
</app-slide-panel>
}

<!-- Edit Wallet Slide Panel -->
<app-slide-panel
Expand Down
52 changes: 51 additions & 1 deletion apps/web/src/app/features/account/settings/settings.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,23 @@ import {
TransactionService,
WebhookEndpointService,
TopupService,
ConfigService,
} from '../../../data';
import {
BusinessProfileFormComponent,
ExternalWalletFormComponent,
PersonFormComponent,
SettingsCardComponent,
SlidePanelComponent,
} from '../../../shared';
import { SlidePanelComponent } from '../../../shared';

@Component({
selector: 'app-settings',
imports: [
SlidePanelComponent,
PersonFormComponent,
ExternalWalletFormComponent,
BusinessProfileFormComponent,
SettingsCardComponent,
],
templateUrl: './settings.component.html',
Expand All @@ -43,6 +46,8 @@ import { SlidePanelComponent } from '../../../shared';
export class SettingsComponent implements OnInit {
@ViewChild('editPersonForm') editPersonForm!: PersonFormComponent;
@ViewChild('editWalletForm') editWalletForm!: ExternalWalletFormComponent;
@ViewChild('editBusinessForm')
editBusinessForm!: BusinessProfileFormComponent;

readonly personService = inject(PersonService);
readonly externalWalletService = inject(ExternalWalletService);
Expand All @@ -53,6 +58,7 @@ export class SettingsComponent implements OnInit {
readonly webhookEndpointService = inject(WebhookEndpointService);
readonly apiKeyService = inject(ApiKeyService);
readonly topupService = inject(TopupService);
readonly configService = inject(ConfigService);
readonly router = inject(Router);
private readonly metaService = inject(MetaService);

Expand All @@ -67,10 +73,54 @@ export class SettingsComponent implements OnInit {
editWalletShowErrors: WritableSignal<boolean> = signal(false);
walletFormValid: WritableSignal<boolean> = signal(false);

// Edit business details panel state
editBusinessPanelOpen: WritableSignal<boolean> = signal(false);
editBusinessLoading: WritableSignal<boolean> = signal(false);
editBusinessShowErrors: WritableSignal<boolean> = signal(false);

ngOnInit(): void {
this.metaService.SetMetaTitle('Settings');
}

// Edit Business Panel
OnEditBusinessClick(): void {
this.editBusinessShowErrors.set(false);
this.editBusinessPanelOpen.set(true);
}

OnEditBusinessPanelClosed(): void {
this.editBusinessPanelOpen.set(false);
this.editBusinessShowErrors.set(false);
}

async OnEditBusinessSubmit(): Promise<void> {
if (!this.editBusinessForm) return;

this.editBusinessShowErrors.set(true);

if (!this.editBusinessForm.ValidateAll()) {
return;
}

const account = this.GetAccount();
if (!account) return;

this.editBusinessLoading.set(true);

try {
const updateData = this.editBusinessForm.GetUpdateData();
await this.accountService.UpdateAccount(account.id, updateData);
this.configService.ClearConfig();
await this.configService.LoadConfig();
this.editBusinessPanelOpen.set(false);
this.editBusinessShowErrors.set(false);
} catch (error) {
console.error('Failed to update business details:', error);
} finally {
this.editBusinessLoading.set(false);
}
}

// Edit Person Panel
OnEditPersonClick(): void {
this.editPersonShowErrors.set(false);
Expand Down
Loading
Loading