chore: move api to api folder and seperate the types into another file

This commit is contained in:
Koosha Lahouti
2025-08-15 15:21:34 +03:30
parent 5a72b597c8
commit 0b42f4ccba
22 changed files with 845 additions and 1402 deletions

View File

@@ -1,4 +1,4 @@
import { useState, useEffect } from 'react';
import { useState, useEffect, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { CardContainer } from '@/components/CardContainer';
import { PageWrapper } from '../PageWrapper';
@@ -7,8 +7,14 @@ import SocialMediaMenu from './socialMedia/SocialMediaMenu';
import SocialMediaDialog from './socialMedia/SocialMediaDialog';
import useMediaQuery from '@mui/material/useMediaQuery';
import type { Theme } from '@mui/material/styles';
import apiClient from '@/lib/apiClient';
import { Box, CircularProgress, Typography } from '@mui/material';
import { useManualApi } from '@/hooks/useApi';
import {
fetchProfile,
sendEmailCode,
confirmEmailCode,
changeEmail,
} from '../../api/settingsApi';
interface EmailAccount {
email: string;
@@ -16,31 +22,8 @@ interface EmailAccount {
time: string;
}
interface GetProfileApiResponse {
success: boolean;
message?: string;
email?: string;
}
interface SendCodeApiResponse {
success: boolean;
message?: string;
}
interface ConfirmCodeApiResponse {
success: boolean;
confirm?: boolean;
message?: string;
}
interface ChangeEmailApiResponse {
success: boolean;
message?: string;
}
export function SocialMedia() {
const { t } = useTranslation('setting');
const token = localStorage.getItem('authToken');
const [openDialog, setOpenDialog] = useState(false);
const [emailInput, setEmailInput] = useState('');
@@ -48,12 +31,36 @@ export function SocialMedia() {
const [dialogStep, setDialogStep] = useState<'enterEmail' | 'enterCode'>(
'enterEmail',
);
const [apiError, setApiError] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [emailList, setEmailList] = useState<EmailAccount[]>([]);
const [formError, setFormError] = useState<string | null>(null);
const [isFetching, setIsFetching] = useState(true);
const [fetchError, setFetchError] = useState<string | null>(null);
const {
data: profileData,
loading: isFetching,
error: fetchError,
execute: executeFetchProfile,
} = useManualApi(fetchProfile);
const {
data: sendCodeData,
loading: isSendingCode,
error: sendCodeError,
execute: executeSendCode,
} = useManualApi(sendEmailCode);
const {
data: confirmData,
loading: isConfirming,
error: confirmError,
execute: executeConfirmCode,
} = useManualApi(confirmEmailCode);
const {
data: changeEmailData,
loading: isChangingEmail,
error: changeEmailError,
execute: executeChangeEmail,
} = useManualApi(changeEmail);
const fullScreen = useMediaQuery((theme: Theme) =>
theme.breakpoints.down('sm'),
@@ -67,128 +74,85 @@ export function SocialMedia() {
| 'xl';
useEffect(() => {
const fetchInitialEmail = async () => {
setIsFetching(true);
setFetchError(null);
if (!token) {
setIsFetching(false);
setFetchError(t('settingForm.notLoggedIn'));
return;
}
try {
const res = await apiClient.post<GetProfileApiResponse>(
'/Profile/GetProfile',
{},
{ headers: { Authorization: `Bearer ${token}` } },
);
executeFetchProfile();
}, []);
if (res.data.success && res.data.email) {
const userEmail = res.data.email;
const newAccount: EmailAccount = {
email: userEmail,
provider: userEmail.includes('gmail.com') ? 'google' : 'email',
time: '',
};
setEmailList([newAccount]);
} else if (!res.data.success) {
throw new Error(res.data.message || t('settingForm.failFetchEmail'));
}
} catch (err: unknown) {
let message = t('settingForm.errorFetchEmail');
if (err instanceof Error) {
message = err.message;
}
setFetchError(message);
} finally {
setIsFetching(false);
}
};
useEffect(() => {
if (profileData?.success && profileData.email) {
const { email } = profileData;
setEmailList([
{
email,
provider: email.includes('@gmail.') ? 'google' : 'email',
time: '',
},
]);
}
}, [profileData]);
fetchInitialEmail();
}, [token, t]);
useEffect(() => {
if (sendCodeData?.success) {
setDialogStep('enterCode');
}
}, [sendCodeData]);
useEffect(() => {
if (confirmData?.success && confirmData.confirm) {
executeChangeEmail({ email: emailInput });
}
}, [confirmData, emailInput, executeChangeEmail]);
useEffect(() => {
if (changeEmailData?.success) {
setEmailList((prev) => [
...prev,
{
email: emailInput,
provider: emailInput.includes('@gmail.') ? 'google' : 'email',
time: t('settingForm.justNow'),
},
]);
resetDialog();
}
}, [changeEmailData, emailInput, t]);
const resetDialog = () => {
setOpenDialog(false);
setEmailInput('');
setVerificationCode('');
setApiError(null);
setIsLoading(false);
setFormError(null);
setDialogStep('enterEmail');
};
const handleSendCode = async () => {
const handleSendCode = () => {
if (!/^\S+@\S+\.\S+$/.test(emailInput)) {
setApiError(t('settingForm.emailIsInvalid'));
setFormError(t('settingForm.emailIsInvalid'));
return;
}
setIsLoading(true);
setApiError(null);
try {
const res = await apiClient.post<SendCodeApiResponse>(
'Profile/SendEmailChangeCode',
{ email: emailInput },
{ headers: { Authorization: `Bearer ${token}` } },
);
if (res.data.success) {
setDialogStep('enterCode');
} else {
setApiError(res.data.message || t('settingForm.sendCodeFailed'));
}
} catch (err: unknown) {
setApiError(t('settingForm.sendCodeFailed'));
} finally {
setIsLoading(false);
}
setFormError(null);
executeSendCode({ email: emailInput });
};
const handleConfirmAndChangeEmail = async () => {
const handleConfirmAndChangeEmail = () => {
if (verificationCode.length < 4) {
setApiError(t('settingForm.verificationCodeRequired'));
setFormError(t('settingForm.verificationCodeRequired'));
return;
}
setIsLoading(true);
setApiError(null);
try {
const confirmRes = await apiClient.post<ConfirmCodeApiResponse>(
'Profile/ConfirmEmailChangeCode',
{ email: emailInput, verifyCode: verificationCode },
{ headers: { Authorization: `Bearer ${token}` } },
);
if (confirmRes.data.success && confirmRes.data.confirm) {
const changeRes = await apiClient.post<ChangeEmailApiResponse>(
'Profile/ChangeEmail',
{ email: emailInput },
{ headers: { Authorization: `Bearer ${token}` } },
);
if (changeRes.data.success) {
setEmailList((prevList) => [
...prevList,
{
email: emailInput,
provider: 'email',
time: t('settingForm.justNow'),
},
]);
resetDialog();
} else {
setApiError(
changeRes.data.message || t('settingForm.changeEmailFailed'),
);
}
} else {
setApiError(
confirmRes.data.message || t('settingForm.verifyCodeFailed'),
);
}
} catch (err: unknown) {
setApiError(t('settingForm.anErrorOccurred'));
} finally {
setIsLoading(false);
}
setFormError(null);
executeConfirmCode({ email: emailInput, verifyCode: verificationCode });
};
const getErrorMessage = (error: unknown): string | null => {
if (!error) return null;
if (error instanceof Error) return error.message;
return String(error);
};
const apiError = useMemo(
() => getErrorMessage(sendCodeError || confirmError || changeEmailError),
[sendCodeError, confirmError, changeEmailError],
);
return (
<PageWrapper>
<CardContainer
@@ -212,7 +176,9 @@ export function SocialMedia() {
</Box>
) : fetchError ? (
<Box sx={{ textAlign: 'center', p: 4 }}>
<Typography color="error.main">{fetchError}</Typography>
<Typography color="error.main">
{getErrorMessage(fetchError)}
</Typography>
</Box>
) : (
<SocialMediaList t={t} emailList={emailList} />
@@ -225,8 +191,8 @@ export function SocialMedia() {
setEmailInput={setEmailInput}
verificationCode={verificationCode}
setVerificationCode={setVerificationCode}
apiError={apiError}
isLoading={isLoading}
apiError={formError || apiError}
isLoading={isSendingCode || isConfirming || isChangingEmail}
dialogStep={dialogStep}
onSendCode={handleSendCode}
onConfirmEmail={handleConfirmAndChangeEmail}