From 3e23fae993c018ef9837496e613ffff6ab89bd5a Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Tue, 5 Aug 2025 18:59:54 -0700 Subject: [PATCH] feat: add api to connect user completion form to backend --- .../authentication/components/DateOfBirth.tsx | 3 +- .../components/UserCompletionForm.tsx | 66 +++++++++---------- src/lib/authToken.ts | 34 ++++++++++ 3 files changed, 66 insertions(+), 37 deletions(-) create mode 100644 src/lib/authToken.ts diff --git a/src/features/authentication/components/DateOfBirth.tsx b/src/features/authentication/components/DateOfBirth.tsx index c0bcf42..7f0b0e7 100644 --- a/src/features/authentication/components/DateOfBirth.tsx +++ b/src/features/authentication/components/DateOfBirth.tsx @@ -1,4 +1,4 @@ -import { useState, useMemo } from 'react'; +import { useMemo } from 'react'; import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import { LocalizationProvider } from '@mui/x-date-pickers'; import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; @@ -12,7 +12,6 @@ interface DateOfBirthProps { export function DateOfBirth({ value, onChange }: DateOfBirthProps) { const { t, i18n } = useTranslation('completionForm'); const isFarsi = i18n.language === 'fa' || i18n.language === 'fa-IR'; - // const [birthDate, setBirthDate] = useState(null); const Adapter = useMemo(() => { return isFarsi ? AdapterDateFnsJalali : AdapterDateFns; diff --git a/src/features/authentication/components/UserCompletionForm.tsx b/src/features/authentication/components/UserCompletionForm.tsx index d35ba09..91a257a 100644 --- a/src/features/authentication/components/UserCompletionForm.tsx +++ b/src/features/authentication/components/UserCompletionForm.tsx @@ -1,15 +1,17 @@ +import React, { useEffect, useState } from 'react'; import { Box, Typography } from '@mui/material'; -import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import Logo from '@/components/Logo'; import { PersonalInfoFields } from './PersonalInfoFields'; import { PasswordSection } from './PasswordSection'; import { EmailSection } from './EmailSection'; import { SubmitSection } from './SubmitSection'; -import Logo from '@/components/Logo'; import apiClient from '@/lib/apiClient'; +import { loginWithPassword } from '@/lib/authToken'; export function UserCompletionForm() { const { t } = useTranslation('completionForm'); + const USERNAME = '+989353989651'; const [firstName, setFirstName] = useState(''); const [lastName, setLastName] = useState(''); @@ -61,11 +63,9 @@ export function UserCompletionForm() { }, [password, validPassword]); useEffect(() => { - let timer: ReturnType; + let timer: NodeJS.Timeout; if (buttonState === 'counting' && countdown > 0) { - timer = setInterval(() => { - setCountdown((prev) => prev - 1); - }, 1000); + timer = setInterval(() => setCountdown((prev) => prev - 1), 1000); } if (countdown === 0) { setButtonState('default'); @@ -74,7 +74,7 @@ export function UserCompletionForm() { }, [buttonState, countdown]); const toPersianDigits = (str: string) => - str.replace(/\d/g, (d: string) => '۰۱۲۳۴۵۶۷۸۹'[parseInt(d)]); + str.replace(/\d/g, (d) => '۰۱۲۳۴۵۶۷۸۹'[parseInt(d, 10)]); const getButtonLabel = () => { if (buttonState === 'sent') return t('completion.sent'); @@ -108,40 +108,39 @@ export function UserCompletionForm() { setCodeSent(false); setEmailVerified(false); }; - const STATICTOKEN = 'Bearer abcdef1234567890'; const handleSubmit = async () => { setLoading(true); setError(null); setSuccess(false); + try { + await loginWithPassword(USERNAME, password); + const { data } = await apiClient.post<{ success: boolean; errorCode: number; message: string; validations: { property: string; message: string }[]; - }>( - '/User/CompleteUserInformation', - { - firstName, - lastName, - gender: sex === 'female' ? 2 : 1, - nationalId, - savePassword: showPasswordSection, - password: showPasswordSection ? password : undefined, - saveEmail: showEmail, - email: showEmail ? email : undefined, - birthDate, - }, - { headers: { Authorization: STATICTOKEN } }, - ); + }>('/User/CompleteUserInformation', { + firstName, + lastName, + gender: sex === 'female' ? 2 : 1, + nationalId, + savePassword: showPasswordSection, + password: showPasswordSection ? password : undefined, + saveEmail: showEmail, + email: showEmail ? email : undefined, + birthDate, + }); + if (data.success) { setSuccess(true); } else { setError(data.message || 'Validation error'); } - } catch (err) { - setError((err as Error).message || 'An error occurred'); + } catch (err: any) { + setError(err.message || 'An error occurred'); } finally { setLoading(false); } @@ -152,8 +151,8 @@ export function UserCompletionForm() { sx={{ backgroundColor: 'background.default', minHeight: '100vh', - flexDirection: 'column', display: 'flex', + flexDirection: 'column', justifyContent: 'center', alignItems: 'center', p: { xs: 1, sm: 2, md: 3 }, @@ -165,7 +164,7 @@ export function UserCompletionForm() { - + {t('completion.title')} @@ -190,6 +182,7 @@ export function UserCompletionForm() { {t('completion.description')} + + + + { + const body = new URLSearchParams(); + body.set('grant_type', 'password'); + body.set('username', username); + body.set('password', password); + body.set('client_id', 'harmony_identity'); + body.set('scope', 'openid harmony_identity profile offline_access'); + + const { data } = await authClient.post( + '/connect/token', + body.toString(), + ); + + localStorage.setItem('authToken', data.access_token); + return data; +}