refactor: enhance customer creation code

This commit is contained in:
Abdalhamid Alhamad
2025-01-13 16:42:27 +03:00
parent 221f3bae4f
commit 5aa3d3774d
6 changed files with 70 additions and 66 deletions

View File

@ -1,15 +1,10 @@
import React, { useState } from 'react';
import {
Box,
Button,
CircularProgress,
Alert
} from '@mui/material';
import { CloudUpload as CloudUploadIcon } from '@mui/icons-material'; import { CloudUpload as CloudUploadIcon } from '@mui/icons-material';
import { documentApi } from '../../api/client'; import { Alert, Box, Button, CircularProgress } from '@mui/material';
import { DocumentType } from '../../types/document';
import { ApiError } from '../../types/api';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import React, { useState } from 'react';
import { documentApi } from '../../api/client';
import { ApiError } from '../../types/api';
import { DocumentType } from '../../types/document';
interface DocumentUploadProps { interface DocumentUploadProps {
onUploadSuccess: (documentId: string) => void; onUploadSuccess: (documentId: string) => void;
@ -41,7 +36,7 @@ export const DocumentUpload = ({ onUploadSuccess, documentType, label }: Documen
if (err instanceof AxiosError && err.response?.data) { if (err instanceof AxiosError && err.response?.data) {
const apiError = err.response.data as ApiError; const apiError = err.response.data as ApiError;
const messages = Array.isArray(apiError.message) const messages = Array.isArray(apiError.message)
? apiError.message.map(m => `${m.field}: ${m.message}`).join('\n') ? apiError.message.map((m) => `${m.field}: ${m.message}`).join('\n')
: apiError.message; : apiError.message;
setError(messages); setError(messages);
} else { } else {
@ -52,17 +47,18 @@ export const DocumentUpload = ({ onUploadSuccess, documentType, label }: Documen
} }
}; };
const now = new Date();
return ( return (
<Box> <Box>
<input <input
accept="image/*,.pdf" accept="image/*,.pdf"
style={{ display: 'none' }} style={{ display: 'none' }}
id={`upload-${documentType}`} id={`upload-${documentType}-${now.getTime()}`}
type="file" type="file"
onChange={handleFileChange} onChange={handleFileChange}
disabled={loading} disabled={loading}
/> />
<label htmlFor={`upload-${documentType}`}> <label htmlFor={`upload-${documentType}-${now.getTime()}`}>
<Button <Button
variant="outlined" variant="outlined"
component="span" component="span"

View File

@ -61,7 +61,7 @@ export class AuthService {
this.logger.log(`Verifying user with phone number ${verifyUserDto.countryCode + verifyUserDto.phoneNumber}`); this.logger.log(`Verifying user with phone number ${verifyUserDto.countryCode + verifyUserDto.phoneNumber}`);
const user = await this.userService.findUserOrThrow({ phoneNumber: verifyUserDto.phoneNumber }); const user = await this.userService.findUserOrThrow({ phoneNumber: verifyUserDto.phoneNumber });
if (user.isPasswordSet) { if (user.isProfileCompleted) {
this.logger.error( this.logger.error(
`User with phone number ${verifyUserDto.countryCode + verifyUserDto.phoneNumber} already verified`, `User with phone number ${verifyUserDto.countryCode + verifyUserDto.phoneNumber} already verified`,
); );
@ -82,7 +82,18 @@ export class AuthService {
throw new BadRequestException('USERS.INVALID_OTP'); throw new BadRequestException('USERS.INVALID_OTP');
} }
const updatedUser = await this.userService.verifyUserAndCreateCustomer(user); if (user.isPhoneVerified) {
this.logger.log(
`User with phone number ${
verifyUserDto.countryCode + verifyUserDto.phoneNumber
} already verified but did not complete registration process`,
);
const tokens = await this.generateAuthToken(user);
return [tokens, user];
}
const updatedUser = await this.userService.verifyUserAndCreateCustomer(user.id);
const tokens = await this.generateAuthToken(updatedUser); const tokens = await this.generateAuthToken(updatedUser);
this.logger.log( this.logger.log(

View File

@ -1,8 +1,9 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from '@nestjs/typeorm';
import { FindOptionsWhere, Repository } from 'typeorm'; import { FindOptionsWhere, Repository } from 'typeorm';
import { Roles } from '~/auth/enums'; import { Guardian } from '~/guardian/entities/guradian.entity';
import { User } from '~/user/entities'; import { CreateJuniorRequestDto } from '~/junior/dtos/request';
import { Junior } from '~/junior/entities';
import { UpdateNotificationsSettingsRequestDto } from '../dtos/request'; import { UpdateNotificationsSettingsRequestDto } from '../dtos/request';
import { Customer } from '../entities'; import { Customer } from '../entities';
import { CustomerNotificationSettings } from '../entities/customer-notification-settings.entity'; import { CustomerNotificationSettings } from '../entities/customer-notification-settings.entity';
@ -19,14 +20,35 @@ export class CustomerRepository {
return this.customerRepository.findOne({ where, relations: ['profilePicture'] }); return this.customerRepository.findOne({ where, relations: ['profilePicture'] });
} }
createCustomer(customerData: Partial<Customer>, user: User) { createJuniorCustomer(guardianId: string, userId: string, body: CreateJuniorRequestDto) {
return this.customerRepository.save( return this.customerRepository.save(
this.customerRepository.create({ this.customerRepository.create({
...customerData, firstName: body.firstName,
id: user.id, lastName: body.lastName,
user, dateOfBirth: body.dateOfBirth,
isGuardian: user.roles.includes(Roles.GUARDIAN), junior: Junior.create({
isJunior: user.roles.includes(Roles.JUNIOR), id: userId,
guardianId,
relationship: body.relationship,
civilIdFrontId: body.civilIdFrontId,
civilIdBackId: body.civilIdBackId,
}),
id: userId,
userId,
isJunior: true,
notificationSettings: new CustomerNotificationSettings(),
}),
);
}
createGuardianCustomer(userId: string) {
return this.customerRepository.save(
this.customerRepository.create({
notificationSettings: new CustomerNotificationSettings(),
guardian: Guardian.create({ id: userId }),
id: userId,
userId,
isGuardian: true,
}), }),
); );
} }

View File

@ -1,6 +1,6 @@
import { BadRequestException, Injectable, Logger } from '@nestjs/common'; import { BadRequestException, Injectable, Logger } from '@nestjs/common';
import { DocumentService, OciService } from '~/document/services'; import { DocumentService, OciService } from '~/document/services';
import { User } from '~/user/entities'; import { CreateJuniorRequestDto } from '~/junior/dtos/request';
import { DeviceService } from '~/user/services'; import { DeviceService } from '~/user/services';
import { UpdateCustomerRequestDto, UpdateNotificationsSettingsRequestDto } from '../dtos/request'; import { UpdateCustomerRequestDto, UpdateNotificationsSettingsRequestDto } from '../dtos/request';
import { Customer } from '../entities'; import { Customer } from '../entities';
@ -42,9 +42,14 @@ export class CustomerService {
return this.findCustomerById(userId); return this.findCustomerById(userId);
} }
createCustomer(customerData: Partial<Customer>, user: User) { createJuniorCustomer(guardianId: string, juniorId: string, body: CreateJuniorRequestDto) {
this.logger.log(`Creating customer for user ${user.id}`); this.logger.log(`Creating customer for user ${juniorId}`);
return this.customerRepository.createCustomer(customerData, user); return this.customerRepository.createJuniorCustomer(guardianId, juniorId, body);
}
createGuardianCustomer(userId: string) {
this.logger.log(`Creating guardian customer for user ${userId}`);
return this.customerRepository.createGuardianCustomer(userId);
} }
async findCustomerById(id: string) { async findCustomerById(id: string) {

View File

@ -2,7 +2,6 @@ import { BadRequestException, Injectable, Logger } from '@nestjs/common';
import { Transactional } from 'typeorm-transactional'; import { Transactional } from 'typeorm-transactional';
import { Roles } from '~/auth/enums'; import { Roles } from '~/auth/enums';
import { PageOptionsRequestDto } from '~/core/dtos'; import { PageOptionsRequestDto } from '~/core/dtos';
import { CustomerNotificationSettings } from '~/customer/entities/customer-notification-settings.entity';
import { CustomerService } from '~/customer/services'; import { CustomerService } from '~/customer/services';
import { DocumentService, OciService } from '~/document/services'; import { DocumentService, OciService } from '~/document/services';
import { UserService } from '~/user/services'; import { UserService } from '~/user/services';
@ -42,22 +41,7 @@ export class JuniorService {
roles: [Roles.JUNIOR], roles: [Roles.JUNIOR],
}); });
await this.customerService.createCustomer( await this.customerService.createJuniorCustomer(guardianId, user.id, body);
{
firstName: body.firstName,
lastName: body.lastName,
dateOfBirth: body.dateOfBirth,
junior: Junior.create({
id: user.id,
guardianId,
relationship: body.relationship,
civilIdFrontId: body.civilIdFrontId,
civilIdBackId: body.civilIdBackId,
}),
notificationSettings: new CustomerNotificationSettings(),
},
user,
);
this.logger.log(`Junior ${user.id} created successfully`); this.logger.log(`Junior ${user.id} created successfully`);

View File

@ -1,9 +1,7 @@
import { BadRequestException, forwardRef, Inject, Injectable, Logger } from '@nestjs/common'; import { BadRequestException, forwardRef, Inject, Injectable, Logger } from '@nestjs/common';
import { FindOptionsWhere } from 'typeorm'; import { FindOptionsWhere } from 'typeorm';
import { Transactional } from 'typeorm-transactional'; import { Transactional } from 'typeorm-transactional';
import { CustomerNotificationSettings } from '~/customer/entities/customer-notification-settings.entity';
import { CustomerService } from '~/customer/services'; import { CustomerService } from '~/customer/services';
import { Guardian } from '~/guardian/entities/guradian.entity';
import { CreateUnverifiedUserRequestDto } from '../../auth/dtos/request'; import { CreateUnverifiedUserRequestDto } from '../../auth/dtos/request';
import { Roles } from '../../auth/enums'; import { Roles } from '../../auth/enums';
import { User } from '../entities'; import { User } from '../entities';
@ -43,7 +41,7 @@ export class UserService {
this.logger.log(`User with phone number ${phoneNumber} not found, creating new user`); this.logger.log(`User with phone number ${phoneNumber} not found, creating new user`);
return this.userRepository.createUnverifiedUser({ phoneNumber, countryCode, roles: [Roles.GUARDIAN] }); return this.userRepository.createUnverifiedUser({ phoneNumber, countryCode, roles: [Roles.GUARDIAN] });
} }
if (user && user.roles.includes(Roles.GUARDIAN) && user.isPasswordSet) { if (user && user.roles.includes(Roles.GUARDIAN) && user.isProfileCompleted) {
this.logger.error(`User with phone number ${phoneNumber} already exists`); this.logger.error(`User with phone number ${phoneNumber} already exists`);
throw new BadRequestException('USERS.PHONE_NUMBER_ALREADY_EXISTS'); throw new BadRequestException('USERS.PHONE_NUMBER_ALREADY_EXISTS');
} }
@ -91,30 +89,18 @@ export class UserService {
this.logger.log(`Creating google user with googleId ${googleId} and email ${email}`); this.logger.log(`Creating google user with googleId ${googleId} and email ${email}`);
const user = await this.userRepository.createUser({ googleId, email, roles: [Roles.GUARDIAN] }); const user = await this.userRepository.createUser({ googleId, email, roles: [Roles.GUARDIAN] });
await this.customerService.createCustomer( await this.customerService.createGuardianCustomer(user.id);
{
guardian: Guardian.create({ id: user.id }),
notificationSettings: new CustomerNotificationSettings(),
},
user,
);
return this.findUserOrThrow({ id: user.id }); return this.findUserOrThrow({ id: user.id });
} }
@Transactional() @Transactional()
async verifyUserAndCreateCustomer(user: User) { async verifyUserAndCreateCustomer(userId: string) {
this.logger.log(`Verifying user ${user.id} and creating customer`); this.logger.log(`Verifying user ${userId} and creating customer`);
await this.userRepository.update(user.id, { isPhoneVerified: true }); await this.userRepository.update(userId, { isPhoneVerified: true });
await this.customerService.createCustomer( await this.customerService.createGuardianCustomer(userId);
{
guardian: Guardian.create({ id: user.id }),
notificationSettings: new CustomerNotificationSettings(),
},
user,
);
this.logger.log(`User ${user.id} verified and customer created successfully`); this.logger.log(`User ${userId} verified and customer created successfully`);
return this.findUserOrThrow({ id: user.id }); return this.findUserOrThrow({ id: userId });
} }
} }