refactor: handle kyc journey for customers

This commit is contained in:
Abdalhamid Alhamad
2025-02-20 16:18:06 +03:00
parent 270753cfd7
commit dae9cb6323
74 changed files with 1116 additions and 477 deletions

View File

@ -0,0 +1,39 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsDateString, IsNotEmpty, IsOptional, IsString, IsUUID } from 'class-validator';
import { i18nValidationMessage as i18n } from 'nestjs-i18n';
import { IsAbove18 } from '~/core/decorators/validations';
export class CreateCustomerRequestDto {
@ApiProperty({ example: 'John' })
@IsString({ message: i18n('validation.IsString', { path: 'general', property: 'customer.firstName' }) })
@IsNotEmpty({ message: i18n('validation.IsNotEmpty', { path: 'general', property: 'customer.firstName' }) })
@IsOptional()
firstName!: string;
@ApiProperty({ example: 'Doe' })
@IsString({ message: i18n('validation.IsString', { path: 'general', property: 'customer.lastName' }) })
@IsNotEmpty({ message: i18n('validation.IsNotEmpty', { path: 'general', property: 'customer.lastName' }) })
@IsOptional()
lastName!: string;
@ApiProperty({ example: 'JO' })
@IsString({ message: i18n('validation.IsString', { path: 'general', property: 'customer.countryOfResidence' }) })
@IsNotEmpty({ message: i18n('validation.IsNotEmpty', { path: 'general', property: 'customer.countryOfResidence' }) })
@IsOptional()
countryOfResidence!: string;
@ApiProperty({ example: '2021-01-01' })
@IsDateString({}, { message: i18n('validation.IsDateString', { path: 'general', property: 'customer.dateOfBirth' }) })
@IsAbove18({ message: i18n('validation.IsAbove18', { path: 'general', property: 'customer.dateOfBirth' }) })
@IsOptional()
dateOfBirth!: Date;
@ApiProperty({ example: 'bf342-3f3f-3f3f-3f3f' })
@IsUUID('4', { message: i18n('validation.IsUUID', { path: 'general', property: 'junior.civilIdFrontId' }) })
@IsOptional()
civilIdFrontId!: string;
@ApiProperty({ example: 'bf342-3f3f-3f3f-3f3f' })
@IsUUID('4', { message: i18n('validation.IsUUID', { path: 'general', property: 'junior.civilIdBackId' }) })
@IsOptional()
civilIdBackId!: string;
}

View File

@ -0,0 +1,23 @@
import { ApiPropertyOptional } from '@nestjs/swagger';
import { IsEnum, IsNotEmpty, IsOptional, IsString } from 'class-validator';
import { i18nValidationMessage as i18n } from 'nestjs-i18n';
import { PageOptionsRequestDto } from '~/core/dtos';
import { KycStatus } from '~/customer/enums';
export class CustomerFiltersRequestDto extends PageOptionsRequestDto {
@IsString({ message: i18n('validation.IsString', { path: 'general', property: 'customer.name' }) })
@IsNotEmpty({ message: i18n('validation.IsNotEmpty', { path: 'general', property: 'customer.name' }) })
@IsOptional()
@ApiPropertyOptional({ description: 'search by name' })
name?: string;
@IsEnum(KycStatus, { message: i18n('validation.IsEnum', { path: 'general', property: 'customer.kycStatus' }) })
@IsOptional()
@ApiPropertyOptional({
enum: KycStatus,
enumName: 'KycStatus',
example: KycStatus.PENDING,
description: 'kyc status of the customer',
})
kycStatus?: string;
}

View File

@ -1,2 +1,4 @@
export * from './create-customer.request.dto';
export * from './customer-filters.request.dto';
export * from './reject-customer-kyc.request.dto';
export * from './update-customer.request.dto';
export * from './update-notifications-settings.request.dto';

View File

@ -0,0 +1,11 @@
import { ApiPropertyOptional } from '@nestjs/swagger';
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
import { i18nValidationMessage as i18n } from 'nestjs-i18n';
export class RejectCustomerKycRequestDto {
@ApiPropertyOptional({ description: 'reason for rejecting the customer kyc' })
@IsString({ message: i18n('validation.IsString', { path: 'general', property: 'customer.rejectionReason' }) })
@IsNotEmpty({ message: i18n('validation.IsNotEmpty', { path: 'general', property: 'customer.rejectionReason' }) })
@IsOptional({ message: i18n('validation.IsOptional', { path: 'general', property: 'customer.rejectionReason' }) })
reason?: string;
}

View File

@ -1,32 +1,8 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsDateString, IsNotEmpty, IsOptional, IsString, IsUUID } from 'class-validator';
import { ApiProperty, PartialType } from '@nestjs/swagger';
import { IsOptional, IsUUID } from 'class-validator';
import { i18nValidationMessage as i18n } from 'nestjs-i18n';
import { IsAbove18 } from '~/core/decorators/validations';
export class UpdateCustomerRequestDto {
@ApiProperty({ example: 'John' })
@IsString({ message: i18n('validation.IsString', { path: 'general', property: 'customer.firstName' }) })
@IsNotEmpty({ message: i18n('validation.IsNotEmpty', { path: 'general', property: 'customer.firstName' }) })
@IsOptional()
firstName!: string;
@ApiProperty({ example: 'Doe' })
@IsString({ message: i18n('validation.IsString', { path: 'general', property: 'customer.lastName' }) })
@IsNotEmpty({ message: i18n('validation.IsNotEmpty', { path: 'general', property: 'customer.lastName' }) })
@IsOptional()
lastName!: string;
@ApiProperty({ example: 'JO' })
@IsString({ message: i18n('validation.IsString', { path: 'general', property: 'customer.countryOfResidence' }) })
@IsNotEmpty({ message: i18n('validation.IsNotEmpty', { path: 'general', property: 'customer.countryOfResidence' }) })
@IsOptional()
countryOfResidence!: string;
@ApiProperty({ example: '2021-01-01' })
@IsDateString({}, { message: i18n('validation.IsDateString', { path: 'general', property: 'customer.dateOfBirth' }) })
@IsAbove18({ message: i18n('validation.IsAbove18', { path: 'general', property: 'customer.dateOfBirth' }) })
@IsOptional()
dateOfBirth!: Date;
import { CreateCustomerRequestDto } from './create-customer.request.dto';
export class UpdateCustomerRequestDto extends PartialType(CreateCustomerRequestDto) {
@ApiProperty({ example: '123e4567-e89b-12d3-a456-426614174000' })
@IsUUID('4', { message: i18n('validation.IsUUID', { path: 'general', property: 'customer.profilePictureId' }) })
@IsOptional()

View File

@ -1,24 +0,0 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsBoolean, IsOptional, IsString, ValidateIf } from 'class-validator';
import { i18nValidationMessage as i18n } from 'nestjs-i18n';
export class UpdateNotificationsSettingsRequestDto {
@ApiProperty()
@IsBoolean({ message: i18n('validation.isBoolean', { path: 'general', property: 'customer.isEmailEnabled' }) })
@IsOptional()
isEmailEnabled!: boolean;
@ApiProperty()
@IsBoolean({ message: i18n('validation.isBoolean', { path: 'general', property: 'customer.isPushEnabled' }) })
@IsOptional()
isPushEnabled!: boolean;
@ApiProperty()
@IsBoolean({ message: i18n('validation.isBoolean', { path: 'general', property: 'customer.isSmsEnabled' }) })
@IsOptional()
isSmsEnabled!: boolean;
@ApiPropertyOptional()
@IsString({ message: i18n('validation.isString', { path: 'general', property: 'auth.fcmToken' }) })
@ValidateIf((o) => o.isPushEnabled)
fcmToken?: string;
}

View File

@ -1,17 +1,20 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Customer } from '~/customer/entities';
import { CustomerStatus, KycStatus } from '~/customer/enums';
import { DocumentMetaResponseDto } from '~/document/dtos/response';
import { NotificationSettingsResponseDto } from './notification-settings.response.dto';
export class CustomerResponseDto {
@ApiProperty()
id!: string;
@ApiProperty()
customerStatus!: string;
customerStatus!: CustomerStatus;
@ApiProperty()
rejectionReason!: string;
kycStatus!: KycStatus;
@ApiProperty()
rejectionReason!: string | null;
@ApiProperty()
firstName!: string;
@ -52,15 +55,13 @@ export class CustomerResponseDto {
@ApiProperty()
isGuardian!: boolean;
@ApiProperty()
notificationSettings!: NotificationSettingsResponseDto;
@ApiPropertyOptional({ type: DocumentMetaResponseDto })
profilePicture!: DocumentMetaResponseDto | null;
constructor(customer: Customer) {
this.id = customer.id;
this.customerStatus = customer.customerStatus;
this.kycStatus = customer.kycStatus;
this.rejectionReason = customer.rejectionReason;
this.firstName = customer.firstName;
this.lastName = customer.lastName;
@ -75,7 +76,7 @@ export class CustomerResponseDto {
this.gender = customer.gender;
this.isJunior = customer.isJunior;
this.isGuardian = customer.isGuardian;
this.notificationSettings = new NotificationSettingsResponseDto(customer.notificationSettings);
this.profilePicture = customer.profilePicture ? new DocumentMetaResponseDto(customer.profilePicture) : null;
}
}

View File

@ -1,2 +1 @@
export * from './customer-response.dto';
export * from './notification-settings.response.dto';

View File

@ -1,19 +0,0 @@
import { ApiProperty } from '@nestjs/swagger';
import { CustomerNotificationSettings } from '~/customer/entities/customer-notification-settings.entity';
export class NotificationSettingsResponseDto {
@ApiProperty()
isEmailEnabled!: boolean;
@ApiProperty()
isPushEnabled!: boolean;
@ApiProperty()
isSmsEnabled!: boolean;
constructor(notificationSettings: CustomerNotificationSettings) {
this.isEmailEnabled = notificationSettings.isEmailEnabled;
this.isPushEnabled = notificationSettings.isPushEnabled;
this.isSmsEnabled = notificationSettings.isSmsEnabled;
}
}