fix: api issue and merge styles problem

This commit is contained in:
Koosha Lahouti
2025-08-18 16:27:43 +03:30
parent 7e5ed6e2fc
commit c61fcf5214
7 changed files with 79 additions and 24 deletions

View File

@@ -55,11 +55,8 @@ export const EnterPasswordForm = ({
useApi(sendSmsOtp); useApi(sendSmsOtp);
const { loading: emailResendLoading, execute: emailResendCall } = const { loading: emailResendLoading, execute: emailResendCall } =
useApi(sendEmailOtp); useApi(sendEmailOtp);
const { const { loading: loginWithPassLoading, execute: loginWithPassCall } =
data: loginWithPassResult, useApi(loginWithPassword);
loading: loginWithPassLoading,
execute: loginWithPassCall,
} = useApi(loginWithPassword);
const auth = useAuth(); const auth = useAuth();
const handleBlur = () => { const handleBlur = () => {

View File

@@ -20,11 +20,29 @@ export async function fetchProfile() {
export async function saveProfile(payload: { export async function saveProfile(payload: {
data: InfoRowData; data: InfoRowData;
imageUrl: string | null; imageUrl: File | null;
}) { }) {
const { data, imageUrl } = payload;
const formData = new FormData();
formData.append('FirstName', data.firstName || '');
formData.append('LastName', data.lastName || '');
formData.append('NationalCode', data.nationalCode || '');
formData.append('Gender', String(data.gender));
formData.append('CountryCode', data.country || '');
if (imageUrl) {
formData.append('Image', imageUrl);
}
return apiClient.post<SaveProfileApiResponse>( return apiClient.post<SaveProfileApiResponse>(
'/Profile/SaveProfilePersonalInforamtion', '/Profile/SaveProfilePersonalInforamtion',
payload, formData,
{
headers: {
'Content-Type': 'multipart/form-data',
},
},
); );
} }
@@ -70,7 +88,7 @@ export async function deleteSessions(payload: { keys: string[] }) {
); );
} }
export async function addPassword(payload: { password: string }) { export async function addPassword(payload: { newPassword: string }) {
return apiClient.post<PasswordApiResponse>('/Profile/AddPassword', payload); return apiClient.post<PasswordApiResponse>('/Profile/AddPassword', payload);
} }

View File

@@ -14,6 +14,7 @@ import {
import { CloseCircle } from 'iconsax-react'; import { CloseCircle } from 'iconsax-react';
import { Icon } from '@rkheftan/harmony-ui'; import { Icon } from '@rkheftan/harmony-ui';
import { type PasswordDialogProps } from '../../types/settingsType'; import { type PasswordDialogProps } from '../../types/settingsType';
import { PasswordValidationItem } from './PasswordValidation';
export function PasswordDialog({ export function PasswordDialog({
open, open,
@@ -33,6 +34,10 @@ export function PasswordDialog({
changePassword, changePassword,
apiError, apiError,
t, t,
hasMinLength,
hasNumber,
hasUpperAndLower,
hasSpecialChar,
}: PasswordDialogProps) { }: PasswordDialogProps) {
return ( return (
<Dialog <Dialog
@@ -93,18 +98,28 @@ export function PasswordDialog({
fullWidth fullWidth
value={password} value={password}
onChange={(e) => setPassword(e.target.value)} onChange={(e) => setPassword(e.target.value)}
sx={{ '& .MuiOutlinedInput-root': { borderRadius: 2 } }} sx={{ '& .MuiOutlinedInput-root': { borderRadius: 2 }, mt: 2 }}
/> />
{showValidation && ( {showValidation && (
<Typography <Box sx={{ mt: 1 }}>
variant="body2" <PasswordValidationItem
color={validPassword ? 'success.main' : 'error.main'} isValid={hasNumber}
> label={t('securityForm.hasNumber')}
{validPassword />
? t('securityForm.passwordIsValid') <PasswordValidationItem
: t('securityForm.passwordIsInvalid')} isValid={hasMinLength}
</Typography> label={t('securityForm.hasMinLength')}
/>
<PasswordValidationItem
isValid={hasUpperAndLower}
label={t('securityForm.hasUpperAndLower')}
/>
<PasswordValidationItem
isValid={hasSpecialChar}
label={t('securityForm.hasSpecialChar')}
/>
</Box>
)} )}
<TextField <TextField

View File

@@ -100,7 +100,8 @@ export function PasswordSecurity() {
useEffect(() => { useEffect(() => {
if (addError || changeError) { if (addError || changeError) {
showToast({ showToast({
message: getErrorMessage(addError || changeError) || t('error.general'), message:
getErrorMessage(addError || changeError) || t('securityForm.general'),
severity: 'error', severity: 'error',
}); });
} }
@@ -116,7 +117,7 @@ export function PasswordSecurity() {
newPassword: password, newPassword: password,
}); });
} else { } else {
await executeAddPassword({ password }); await executeAddPassword({ newPassword: password });
} }
}; };
@@ -206,6 +207,10 @@ export function PasswordSecurity() {
changePassword={changePasswordUI} changePassword={changePasswordUI}
apiError={getErrorMessage(apiError)} apiError={getErrorMessage(apiError)}
t={t} t={t}
hasMinLength={hasMinLength}
hasNumber={hasNumber}
hasUpperAndLower={hasUpperAndLower}
hasSpecialChar={hasSpecialChar}
/> />
</Box> </Box>
)} )}

View File

@@ -15,6 +15,7 @@ export function PersonalInformation() {
const { t } = useTranslation('setting'); const { t } = useTranslation('setting');
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
const [uploadedImageUrl, setUploadedImageUrl] = useState<string | null>(null); const [uploadedImageUrl, setUploadedImageUrl] = useState<string | null>(null);
const [uploadedImageFile, setUploadedImageFile] = useState<File | null>(null);
const [data, setData] = useState<InfoRowData>({ const [data, setData] = useState<InfoRowData>({
firstName: '', firstName: '',
lastName: '', lastName: '',
@@ -51,7 +52,15 @@ export function PersonalInformation() {
}; };
setData(fetchedData); setData(fetchedData);
setOriginalData(fetchedData); setOriginalData(fetchedData);
setUploadedImageUrl(profileData.profileImageUrl || null);
if (profileData.profileImageUrl) {
const imageBaseUrl = 'https://accounts.business-harmony.com/uploads/';
setUploadedImageUrl(`${imageBaseUrl}${profileData.profileImageUrl}`);
} else {
setUploadedImageUrl(null);
}
setUploadedImageFile(null);
} }
}, [profileData]); }, [profileData]);
@@ -63,6 +72,7 @@ export function PersonalInformation() {
}); });
setIsEditing(false); setIsEditing(false);
setOriginalData(data); setOriginalData(data);
setUploadedImageFile(null);
} }
}, [saveData, data, showToast, t]); }, [saveData, data, showToast, t]);
@@ -78,11 +88,12 @@ export function PersonalInformation() {
if (originalData) { if (originalData) {
setData(originalData); setData(originalData);
} }
setUploadedImageFile(null);
}; };
const handleSaveClick = async () => { const handleSaveClick = async () => {
if (!data) return; if (!data) return;
executeSaveProfile({ data, imageUrl: uploadedImageUrl }); executeSaveProfile({ data, imageUrl: uploadedImageFile });
}; };
const getErrorMessage = (error: unknown): string | null => { const getErrorMessage = (error: unknown): string | null => {
@@ -90,6 +101,7 @@ export function PersonalInformation() {
if (error instanceof Error) return error.message; if (error instanceof Error) return error.message;
return String(error); return String(error);
}; };
useEffect(() => { useEffect(() => {
if (saveProfileError) { if (saveProfileError) {
showToast({ showToast({
@@ -212,12 +224,16 @@ export function PersonalInformation() {
initials={initials} initials={initials}
uploadedImageUrl={uploadedImageUrl} uploadedImageUrl={uploadedImageUrl}
onImageChange={(file) => { onImageChange={(file) => {
setUploadedImageFile(file);
const reader = new FileReader(); const reader = new FileReader();
reader.onload = () => reader.onload = () =>
setUploadedImageUrl(reader.result as string); setUploadedImageUrl(reader.result as string);
reader.readAsDataURL(file); reader.readAsDataURL(file);
}} }}
onRemoveImage={() => setUploadedImageUrl(null)} onRemoveImage={() => {
setUploadedImageFile(null);
setUploadedImageUrl(null);
}}
/> />
)} )}
{data && {data &&

View File

@@ -260,7 +260,7 @@ export function SettingPage() {
})) }))
} }
renderInput={(p) => <TextField {...p} />} renderInput={(p) => <TextField {...p} />}
size="small" size="medium"
fullWidth fullWidth
disableClearable disableClearable
/> />
@@ -288,7 +288,7 @@ export function SettingPage() {
v && setDraftSettings((prev) => ({ ...prev, calendar: v })) v && setDraftSettings((prev) => ({ ...prev, calendar: v }))
} }
renderInput={(params) => <TextField {...params} />} renderInput={(params) => <TextField {...params} />}
size="small" size="medium"
fullWidth fullWidth
disableClearable disableClearable
/> />

View File

@@ -38,6 +38,10 @@ export interface PasswordDialogProps {
changePassword: boolean; changePassword: boolean;
apiError: string | null; apiError: string | null;
t: (key: string) => string; t: (key: string) => string;
hasMinLength: boolean;
hasNumber: boolean;
hasUpperAndLower: boolean;
hasSpecialChar: boolean;
} }
export interface ValidationItemProps { export interface ValidationItemProps {