chore: move api to api folder and seperate the types into another file
This commit is contained in:
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user