mirror of
https://github.com/HamzaSha1/zod-backend.git
synced 2025-08-25 21:59:40 +00:00
refactor: enhance customer creation code
This commit is contained in:
@ -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"
|
||||||
|
@ -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(
|
||||||
|
@ -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,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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`);
|
||||||
|
|
||||||
|
@ -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 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user