feat: add logo image and RTL support styles

- Added logo image to assets.
- Implemented RTL support styles in rtlSupport.scss for various components including breadcrumb, datatable, and tree node toggle button.

chore: configure environment files for production, staging, and development

- Created environment.prod.ts for production settings.
- Created environment.staging.ts for staging settings.
- Created environment.ts for local development settings.

feat: define custom theme preset

- Added presets.ts to define a custom theme preset using PrimeUIX with specific component styles and semantic colors.

chore: set up proxy configuration for local development
This commit is contained in:
2025-12-04 21:07:18 +03:30
parent c58210cdbd
commit 07fec02ea1
164 changed files with 20175 additions and 735 deletions
@@ -0,0 +1,60 @@
<form [formGroup]="form" class="w-full flex flex-col gap-4" (ngSubmit)="submit()">
<app-input label="نام" name="firstName" size="large" [control]="form.controls.firstName" />
<app-input label="نام خانوادگی" name="lastName" size="large" [control]="form.controls.lastName" />
<app-gender-select [control]="form.controls.gender" size="large" />
<app-input
label="شماره تلفن همراه"
name="mobile"
size="large"
autocomplete="tel"
[control]="form.controls.mobile"
type="mobile"
/>
<app-input
label="آدرس ایمیل"
name="email"
size="large"
autocomplete="email"
[control]="form.controls.email"
type="email"
/>
<app-input
label="نام کاربری"
name="username"
size="large"
autocomplete="username"
[control]="form.controls.username"
/>
<uikit-field label="رمز عبور" name="password" pSize="large" [control]="form.controls.password">
<p-password
id="password1"
size="large"
name="password"
formControlName="password"
autocomplete="password"
[toggleMask]="true"
[fluid]="true"
[feedback]="false"
[invalid]="form.controls.password.touched && form.controls.password.invalid"
/>
<span class="text-xs mt-2 text-muted-color">
رمز باید حداقل ۸ کاراکتر بوده و شامل حداقل یک حرف بزرگ، یک حرف کوچک، یک عدد و یک کاراکتر ویژه باشد.
</span>
</uikit-field>
<uikit-field label="تکرار رمز عبور" pSize="large" name="confirmPassword" [control]="form.controls.confirmPassword">
<p-password
id="confirmPassword"
size="large"
name="confirmPassword"
formControlName="confirmPassword"
autocomplete="new-password"
[toggleMask]="true"
[fluid]="true"
[feedback]="false"
[invalid]="form.controls.confirmPassword.touched && form.controls.confirmPassword.invalid"
/>
</uikit-field>
<p-button label="تایید" styleClass="w-full mt-4" size="large" [loading]="isLoading()" type="submit"></p-button>
</form>
@@ -0,0 +1,94 @@
import { AuthService } from '@/core';
import { ISignupRequestPayload, IUserLoginInfo, Maybe, TRoles } from '@/core/models';
import { ToastService } from '@/core/services/toast.service';
import { mobileValidator, MustMatch } from '@/core/validators';
import { password } from '@/core/validators/password.validator';
import { GenderSelectComponent } from '@/shared/catalog';
import { InputComponent } from '@/shared/components';
import { UikitFieldComponent } from '@/uikit/uikit-field.component';
import { CommonModule } from '@angular/common';
import { Component, EventEmitter, inject, Input, Output, signal } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { Button } from 'primeng/button';
import { ImageModule } from 'primeng/image';
import { InputGroupModule } from 'primeng/inputgroup';
import { InputGroupAddonModule } from 'primeng/inputgroupaddon';
import { Password } from 'primeng/password';
import { ProgressSpinnerModule } from 'primeng/progressspinner';
import { RadioButtonModule } from 'primeng/radiobutton';
@Component({
selector: 'auth-signup',
templateUrl: './signup.component.html',
imports: [
CommonModule,
ReactiveFormsModule,
Button,
Password,
ImageModule,
ProgressSpinnerModule,
RadioButtonModule,
InputGroupModule,
InputGroupAddonModule,
UikitFieldComponent,
InputComponent,
GenderSelectComponent,
],
})
export class SignupComponent {
@Input() userLoginInfo!: Partial<IUserLoginInfo>;
@Input() role!: TRoles;
@Output() onSubmit = new EventEmitter<IUserLoginInfo>();
@Output() toLogin = new EventEmitter<void>();
constructor(
private readonly authService: AuthService,
private readonly toastService: ToastService,
private readonly router: Router,
) {}
private readonly fb = inject(FormBuilder);
readonly isLoading = signal<boolean>(false);
readonly errorMessage = signal<string>('');
readonly hidePassword = signal<boolean>(true);
readonly form = this.fb.group(
{
firstName: ['', [Validators.required]],
lastName: ['', [Validators.required]],
gender: [null as Maybe<boolean>, [Validators.required]],
mobile: ['', [Validators.required, mobileValidator()]],
email: ['', [Validators.required, Validators.email]],
username: ['', [Validators.required]],
password: ['', [Validators.required, password()]],
confirmPassword: ['', [Validators.required]],
},
{
validators: [MustMatch('password', 'confirmPassword')],
},
);
submit(): void {
this.form.markAllAsTouched();
if (this.form.invalid) return;
const credentials = this.form.value as ISignupRequestPayload;
this.isLoading.set(true);
this.authService.signup(credentials, this.role).subscribe({
next: () => {
this.toastService.success({
text: 'ثبت نام با موفقیت انجام شد. لطفا وارد شوید.',
});
this.errorMessage.set('');
this.onSubmit?.emit();
this.isLoading.set(false);
},
error: (error) => {
this.isLoading.set(false);
},
});
}
}