ISSUE 6: add confirmation modal before profile pic removal and preview modal on upload

This commit is contained in:
Ayobami
2025-07-01 16:59:55 +01:00
parent 5046be7584
commit 201d9decb3
4 changed files with 314 additions and 109 deletions
+23 -6
View File
@@ -9,19 +9,35 @@ export default function ConfirmationModal() {
if (!state.confirmation) return null; if (!state.confirmation) return null;
return ( return (
<div className={"popup-container z-100 flex items-center justify-center normal-case"}>
<div <div
className={`${state.confirmation ? "pop-in" : "pop-out"} w-[510px] max-w-[80%] rounded-lg bg-white p-5 px-3 md:px-5`} className={
"popup-container z-100 flex items-center justify-center normal-case"
}
>
<div
className={`${
state.confirmation ? "pop-in" : "pop-out"
} w-[510px] max-w-[80%] rounded-lg bg-white p-5 px-3 md:px-5`}
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
<h2 className="mb-4 text-3xl font-semibold"> <h2 className='mb-4 text-3xl font-semibold'>
<GreenCheckIcon /> <GreenCheckIcon />
{state.confirmationHeading} {state.confirmationHeading}
</h2> </h2>
<p className="mb-4 text-sm text-gray-500">{state.confirmationMsg}</p> <p className='mb-4 text-sm text-gray-500'>{state.confirmationMsg}</p>
<div className='flex gap-4 *:w-1/2'>
<button <button
type="button" type='button'
className="login-btn-gradient mt-4 w-full rounded py-2 tracking-wide text-white outline-none focus:outline-none" onClick={() => {
dispatch({ type: "CLOSE_CONFIRMATION" });
}}
className='mt-4 w-full rounded border-2 border-gray-300 py-2 tracking-wide text-black outline-none focus:outline-none'
>
Cancel
</button>
<button
type='button'
className='login-btn-gradient mt-4 w-full rounded py-2 tracking-wide text-white outline-none focus:outline-none'
onClick={() => { onClick={() => {
if (state.confirmationCloseFn) { if (state.confirmationCloseFn) {
state.confirmationCloseFn(); state.confirmationCloseFn();
@@ -33,5 +49,6 @@ export default function ConfirmationModal() {
</button> </button>
</div> </div>
</div> </div>
</div>
); );
} }
@@ -0,0 +1,62 @@
import { Dialog, Transition } from "@headlessui/react";
import { Fragment } from "react";
export default function ProfileImageConfirmModal({
modalOpen,
modalImage,
onConfirm,
onCancel,
}) {
return (
<Transition appear show={modalOpen} as={Fragment}>
<Dialog as='div' className='relative z-10' onClose={onCancel}>
<Transition.Child
as={Fragment}
enter='ease-out duration-300'
enterFrom='opacity-0'
enterTo='opacity-100'
leave='ease-in duration-200'
leaveFrom='opacity-100'
leaveTo='opacity-0'
>
<div className='fixed inset-0 bg-black bg-opacity-25' />
</Transition.Child>
<div className='fixed inset-0 overflow-y-auto'>
<div className='flex min-h-full items-center justify-center p-4 text-center'>
<Transition.Child
as={Fragment}
enter='ease-out duration-300'
enterFrom='opacity-0 scale-95'
enterTo='opacity-100 scale-100'
leave='ease-in duration-200'
leaveFrom='opacity-100 scale-100'
leaveTo='opacity-0 scale-95'
>
<Dialog.Panel className='w-full max-w-sm transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all'>
<img
src={modalImage || "/default.png"}
alt='Profile Preview'
className='mb-4 h-64 w-full rounded object-cover'
/>
<div className='flex justify-center gap-4'>
<button
className='login-btn-gradient rounded px-4 py-2 text-white'
onClick={onConfirm}
>
Confirm
</button>
<button
className='rounded bg-gray-300 px-4 py-2 text-black'
onClick={onCancel}
>
Cancel
</button>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition>
);
}
@@ -8,7 +8,11 @@ import MkdSDK from "@/utils/MkdSDK";
import { callCustomAPI } from "@/utils/callCustomAPI"; import { callCustomAPI } from "@/utils/callCustomAPI";
import Skeleton from "react-loading-skeleton"; import Skeleton from "react-loading-skeleton";
import { formatDate } from "@/utils/date-time-utils"; import { formatDate } from "@/utils/date-time-utils";
import { IMAGE_STATUS, NOTIFICATION_STATUS, NOTIFICATION_TYPE } from "@/utils/constants"; import {
IMAGE_STATUS,
NOTIFICATION_STATUS,
NOTIFICATION_TYPE,
} from "@/utils/constants";
import SwitchBulkMode from "@/components/SwitchBulkMode"; import SwitchBulkMode from "@/components/SwitchBulkMode";
import TwoFaDialog from "@/components/Profile/TwoFaDialog"; import TwoFaDialog from "@/components/Profile/TwoFaDialog";
import EditProfileModal from "@/components/Profile/EditProfileModal"; import EditProfileModal from "@/components/Profile/EditProfileModal";
@@ -18,6 +22,7 @@ import EditAboutModal from "@/components/Profile/EditAboutModal";
import { parseJsonSafely } from "@/utils/utils"; import { parseJsonSafely } from "@/utils/utils";
import EnableEmailDialog from "@/components/Profile/EnableEmailDialog"; import EnableEmailDialog from "@/components/Profile/EnableEmailDialog";
import DeleteAccountModal from "@/components/Profile/DeleteAccountModal"; import DeleteAccountModal from "@/components/Profile/DeleteAccountModal";
import ProfileImageConfirmModal from "@/components/Profile/ProfileImageConfirmModal";
function getProfilePhotoMessage(image_status) { function getProfilePhotoMessage(image_status) {
switch (image_status) { switch (image_status) {
@@ -33,7 +38,8 @@ function getProfilePhotoMessage(image_status) {
} }
export default function CustomerProfilePage() { export default function CustomerProfilePage() {
const { dispatch: globalDispatch, state: globalState } = useContext(GlobalContext); const { dispatch: globalDispatch, state: globalState } =
useContext(GlobalContext);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [twoFa, setTwoFa] = useState(false); const [twoFa, setTwoFa] = useState(false);
const [twoFaDialog, setTwoFaDialog] = useState(false); const [twoFaDialog, setTwoFaDialog] = useState(false);
@@ -49,20 +55,29 @@ export default function CustomerProfilePage() {
const [deleteAccountModal, setDeleteAccountModal] = useState(false); const [deleteAccountModal, setDeleteAccountModal] = useState(false);
const [showImagePreview, setShowImagePreview] = useState(false);
const [selectedImage, setSelectedImage] = useState(null);
let sdk = new MkdSDK(); let sdk = new MkdSDK();
const changeProfilePic = async (e) => { const changeProfilePic = (e) => {
globalDispatch({ type: "START_LOADING" }); const file = e.target.files && e.target.files[0];
const file = e.target.files; if (file) {
const formData = new FormData(); setSelectedImage(file);
for (let i = 0; i < file.length; i++) { setShowImagePreview(true);
formData.append("file", file[i]);
} }
};
const handleConfirmUpload = async () => {
setShowImagePreview(false);
if (!selectedImage) return;
globalDispatch({ type: "START_LOADING" });
const formData = new FormData();
formData.append("file", selectedImage);
try { try {
const upload = await sdk.uploadImage(formData); const upload = await sdk.uploadImage(formData);
console.log("upload", upload);
sdk.setTable("user"); sdk.setTable("user");
const result = await callCustomAPI( await callCustomAPI(
"edit-self", "edit-self",
"post", "post",
{ {
@@ -71,9 +86,16 @@ export default function CustomerProfilePage() {
is_photo_approved: IMAGE_STATUS.IN_REVIEW, is_photo_approved: IMAGE_STATUS.IN_REVIEW,
}, },
}, },
"", ""
); );
globalDispatch({ type: "SET_USER_DATA", payload: { ...globalState.user, photo: upload.url, is_photo_approved: IMAGE_STATUS.IN_REVIEW } }); globalDispatch({
type: "SET_USER_DATA",
payload: {
...globalState.user,
photo: upload.url,
is_photo_approved: IMAGE_STATUS.IN_REVIEW,
},
});
// create notification // create notification
sdk.setTable("notification"); sdk.setTable("notification");
await sdk.callRestAPI( await sdk.callRestAPI(
@@ -86,7 +108,7 @@ export default function CustomerProfilePage() {
type: NOTIFICATION_TYPE.EDIT_USER_PICTURE, type: NOTIFICATION_TYPE.EDIT_USER_PICTURE,
status: NOTIFICATION_STATUS.NOT_ADDRESSED, status: NOTIFICATION_STATUS.NOT_ADDRESSED,
}, },
"POST", "POST"
); );
} catch (err) { } catch (err) {
globalDispatch({ globalDispatch({
@@ -98,9 +120,15 @@ export default function CustomerProfilePage() {
}); });
} }
globalDispatch({ type: "STOP_LOADING" }); globalDispatch({ type: "STOP_LOADING" });
setSelectedImage(null);
}; };
const removeProfilePic = async (e) => { const handleCancelUpload = () => {
setShowImagePreview(false);
setSelectedImage(null);
};
const removeProfilePic = async () => {
try { try {
sdk.setTable("user"); sdk.setTable("user");
await callCustomAPI( await callCustomAPI(
@@ -112,9 +140,12 @@ export default function CustomerProfilePage() {
is_photo_approved: null, is_photo_approved: null,
}, },
}, },
"", ""
); );
globalDispatch({ type: "SET_USER_DATA", payload: { ...globalState.user, photo: null, is_photo_approved: null } }); globalDispatch({
type: "SET_USER_DATA",
payload: { ...globalState.user, photo: null, is_photo_approved: null },
});
} catch (err) { } catch (err) {
globalDispatch({ globalDispatch({
type: "SHOW_ERROR", type: "SHOW_ERROR",
@@ -137,14 +168,16 @@ export default function CustomerProfilePage() {
two_factor_authentication: twoFa != 1 ? 1 : 0, two_factor_authentication: twoFa != 1 ? 1 : 0,
}, },
}, },
"", ""
); );
setTwoFaDialog(false); setTwoFaDialog(false);
globalDispatch({ globalDispatch({
type: "SHOW_CONFIRMATION", type: "SHOW_CONFIRMATION",
payload: { payload: {
heading: "Success", heading: "Success",
message: `Two factor Authentication ${twoFa == 1 ? "disabled" : "enabled"}`, message: `Two factor Authentication ${
twoFa == 1 ? "disabled" : "enabled"
}`,
btn: "Ok got it", btn: "Ok got it",
}, },
}); });
@@ -163,50 +196,66 @@ export default function CustomerProfilePage() {
} }
return ( return (
<div className="pt-[44px] pb-16 normal-case text-[#475467]"> <div className='pb-16 pt-[44px] normal-case text-[#475467]'>
<div className="flex flex-wrap-reverse justify-between "> <div className='flex flex-wrap-reverse justify-between '>
<div className="flex max-w-3xl flex-grow flex-col justify-between md:flex-row md:items-center"> <div className='flex max-w-3xl flex-grow flex-col justify-between md:flex-row md:items-center'>
<div className="mb-[16px] flex flex-col"> <div className='mb-[16px] flex flex-col'>
<h3 className="text-xl font-semibold">Your photo</h3> <h3 className='text-xl font-semibold'>Your photo</h3>
<small className="text-xs md:text-sm">{getProfilePhotoMessage(globalState.user.is_photo_approved)}</small> <small className='text-xs md:text-sm'>
{getProfilePhotoMessage(globalState.user.is_photo_approved)}
</small>
</div> </div>
<div <div
data-tour="photo-step" data-tour='photo-step'
className="flex items-center justify-between"> className='flex items-center justify-between'
>
<img <img
src={globalState.user.photo ?? "/default.png"} src={globalState.user.photo ?? "/default.png"}
alt="" alt=''
className="photo-step h-[56px] w-[56px] rounded-full object-cover md:mr-[65px] md:h-[64px] md:w-[64px]" className='photo-step h-[56px] w-[56px] rounded-full object-cover md:mr-[65px] md:h-[64px] md:w-[64px]'
/> />
<div> <div>
<label <label
className="third-step mr-3 cursor-pointer font-semibold underline" className='third-step mr-3 cursor-pointer font-semibold underline'
htmlFor="profilePic" htmlFor='profilePic'
> >
Update{" "} Update{" "}
<input <input
type="file" type='file'
className="hidden" className='hidden'
id="profilePic" id='profilePic'
onChange={changeProfilePic} onChange={changeProfilePic}
/> />
</label> </label>
<button <button
className="underline" className='underline'
onClick={removeProfilePic} onClick={() => {
globalDispatch({
type: "SHOW_CONFIRMATION",
payload: {
heading: "Remove Profile Picture?",
message:
"Are you sure you want to remove your profile picture?",
btn: "Yes, Remove",
onClose: () => {
removeProfilePic();
},
},
});
}}
> >
Remove Remove
</button> </button>
</div> </div>
</div> </div>
</div> </div>
<div className="mb-12 flex w-full justify-between md:mb-0 md:w-[unset] md:flex-col md:justify-start"> <div className='mb-12 flex w-full justify-between md:mb-0 md:w-[unset] md:flex-col md:justify-start'>
<p className="mb-2 self-end">Profile status</p> <p className='mb-2 self-end'>Profile status</p>
<div data-tour="fourth-step" className="flex fourth-step"> <div data-tour='fourth-step' className='fourth-step flex'>
{![0, 1].includes(globalState.user.verificationStatus) && ( {![0, 1].includes(globalState.user.verificationStatus) && (
<Link <Link
to="/account/verification" to='/account/verification'
className="mr-3 font-semibold text-[#1570EF]" className='mr-3 font-semibold text-[#1570EF]'
> >
Get verified Get verified
</Link> </Link>
@@ -214,7 +263,11 @@ export default function CustomerProfilePage() {
<button <button
className={ className={
`${globalState.user.verificationStatus == 1 ? "login-btn-gradient" : "bg-[#667085]"}` + `${
globalState.user.verificationStatus == 1
? "login-btn-gradient"
: "bg-[#667085]"
}` +
" flex min-w-[103px] items-center gap-1 rounded-md p-1 px-2 text-xs uppercase tracking-wider text-white" " flex min-w-[103px] items-center gap-1 rounded-md p-1 px-2 text-xs uppercase tracking-wider text-white"
} }
> >
@@ -255,7 +308,7 @@ export default function CustomerProfilePage() {
</div> </div>
</div> </div>
<hr className="my-[37px]" /> <hr className='my-[37px]' />
<EditProfileModal <EditProfileModal
closeModal={() => setUpdateName(false)} closeModal={() => setUpdateName(false)}
modalOpen={updateName} modalOpen={updateName}
@@ -284,6 +337,16 @@ export default function CustomerProfilePage() {
isOpen={enableEmailDialog} isOpen={enableEmailDialog}
closeModal={() => setEnableEmailDialog(false)} closeModal={() => setEnableEmailDialog(false)}
/> />
<ProfileImageConfirmModal
modalOpen={showImagePreview}
modalImage={
selectedImage instanceof File
? URL.createObjectURL(selectedImage)
: selectedImage
}
onConfirm={handleConfirmUpload}
onCancel={handleCancelUpload}
/>
</div> </div>
); );
} }
+113 -50
View File
@@ -8,7 +8,11 @@ import MkdSDK from "@/utils/MkdSDK";
import { callCustomAPI } from "@/utils/callCustomAPI"; import { callCustomAPI } from "@/utils/callCustomAPI";
import Skeleton from "react-loading-skeleton"; import Skeleton from "react-loading-skeleton";
import { formatDate } from "@/utils/date-time-utils"; import { formatDate } from "@/utils/date-time-utils";
import { IMAGE_STATUS, NOTIFICATION_STATUS, NOTIFICATION_TYPE } from "@/utils/constants"; import {
IMAGE_STATUS,
NOTIFICATION_STATUS,
NOTIFICATION_TYPE,
} from "@/utils/constants";
import SwitchBulkMode from "@/components/SwitchBulkMode"; import SwitchBulkMode from "@/components/SwitchBulkMode";
import TwoFaDialog from "@/components/Profile/TwoFaDialog"; import TwoFaDialog from "@/components/Profile/TwoFaDialog";
import EditProfileModal from "@/components/Profile/EditProfileModal"; import EditProfileModal from "@/components/Profile/EditProfileModal";
@@ -18,6 +22,7 @@ import EditAboutModal from "@/components/Profile/EditAboutModal";
import { parseJsonSafely } from "@/utils/utils"; import { parseJsonSafely } from "@/utils/utils";
import EnableEmailDialog from "@/components/Profile/EnableEmailDialog"; import EnableEmailDialog from "@/components/Profile/EnableEmailDialog";
import DeleteAccountModal from "@/components/Profile/DeleteAccountModal"; import DeleteAccountModal from "@/components/Profile/DeleteAccountModal";
import ProfileImageConfirmModal from "@/components/Profile/ProfileImageConfirmModal";
function getProfilePhotoMessage(image_status) { function getProfilePhotoMessage(image_status) {
switch (image_status) { switch (image_status) {
@@ -33,7 +38,8 @@ function getProfilePhotoMessage(image_status) {
} }
export default function HostProfilePage() { export default function HostProfilePage() {
const { dispatch: globalDispatch, state: globalState } = useContext(GlobalContext); const { dispatch: globalDispatch, state: globalState } =
useContext(GlobalContext);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [twoFa, setTwoFa] = useState(false); const [twoFa, setTwoFa] = useState(false);
const [twoFaDialog, setTwoFaDialog] = useState(false); const [twoFaDialog, setTwoFaDialog] = useState(false);
@@ -49,20 +55,29 @@ export default function HostProfilePage() {
const [deleteAccountModal, setDeleteAccountModal] = useState(false); const [deleteAccountModal, setDeleteAccountModal] = useState(false);
const [showImagePreview, setShowImagePreview] = useState(false);
const [selectedImage, setSelectedImage] = useState(null);
let sdk = new MkdSDK(); let sdk = new MkdSDK();
const changeProfilePic = async (e) => { const changeProfilePic = (e) => {
globalDispatch({ type: "START_LOADING" }); const file = e.target.files && e.target.files[0];
const file = e.target.files; if (file) {
const formData = new FormData(); setSelectedImage(file);
for (let i = 0; i < file.length; i++) { setShowImagePreview(true);
formData.append("file", file[i]);
} }
};
const handleConfirmUpload = async () => {
setShowImagePreview(false);
if (!selectedImage) return;
globalDispatch({ type: "START_LOADING" });
const formData = new FormData();
formData.append("file", selectedImage);
try { try {
const upload = await sdk.uploadImage(formData); const upload = await sdk.uploadImage(formData);
console.log("upload", upload);
sdk.setTable("user"); sdk.setTable("user");
const result = await callCustomAPI( await callCustomAPI(
"edit-self", "edit-self",
"post", "post",
{ {
@@ -71,9 +86,16 @@ export default function HostProfilePage() {
is_photo_approved: IMAGE_STATUS.IN_REVIEW, is_photo_approved: IMAGE_STATUS.IN_REVIEW,
}, },
}, },
"", ""
); );
globalDispatch({ type: "SET_USER_DATA", payload: { ...globalState.user, photo: upload.url, is_photo_approved: IMAGE_STATUS.IN_REVIEW } }); globalDispatch({
type: "SET_USER_DATA",
payload: {
...globalState.user,
photo: upload.url,
is_photo_approved: IMAGE_STATUS.IN_REVIEW,
},
});
// create notification // create notification
sdk.setTable("notification"); sdk.setTable("notification");
await sdk.callRestAPI( await sdk.callRestAPI(
@@ -86,7 +108,7 @@ export default function HostProfilePage() {
type: NOTIFICATION_TYPE.EDIT_USER_PICTURE, type: NOTIFICATION_TYPE.EDIT_USER_PICTURE,
status: NOTIFICATION_STATUS.NOT_ADDRESSED, status: NOTIFICATION_STATUS.NOT_ADDRESSED,
}, },
"POST", "POST"
); );
} catch (err) { } catch (err) {
globalDispatch({ globalDispatch({
@@ -98,9 +120,15 @@ export default function HostProfilePage() {
}); });
} }
globalDispatch({ type: "STOP_LOADING" }); globalDispatch({ type: "STOP_LOADING" });
setSelectedImage(null);
}; };
const removeProfilePic = async (e) => { const handleCancelUpload = () => {
setShowImagePreview(false);
setSelectedImage(null);
};
const removeProfilePic = async () => {
try { try {
sdk.setTable("user"); sdk.setTable("user");
await callCustomAPI( await callCustomAPI(
@@ -112,9 +140,12 @@ export default function HostProfilePage() {
is_photo_approved: null, is_photo_approved: null,
}, },
}, },
"", ""
); );
globalDispatch({ type: "SET_USER_DATA", payload: { ...globalState.user, photo: null, is_photo_approved: null } }); globalDispatch({
type: "SET_USER_DATA",
payload: { ...globalState.user, photo: null, is_photo_approved: null },
});
} catch (err) { } catch (err) {
globalDispatch({ globalDispatch({
type: "SHOW_ERROR", type: "SHOW_ERROR",
@@ -137,14 +168,16 @@ export default function HostProfilePage() {
two_factor_authentication: twoFa != 1 ? 1 : 0, two_factor_authentication: twoFa != 1 ? 1 : 0,
}, },
}, },
"", ""
); );
setTwoFaDialog(false); setTwoFaDialog(false);
globalDispatch({ globalDispatch({
type: "SHOW_CONFIRMATION", type: "SHOW_CONFIRMATION",
payload: { payload: {
heading: "Success", heading: "Success",
message: `Two factor Authentication ${twoFa == 1 ? "disabled" : "enabled"}`, message: `Two factor Authentication ${
twoFa == 1 ? "disabled" : "enabled"
}`,
btn: "Ok got it", btn: "Ok got it",
}, },
}); });
@@ -163,51 +196,67 @@ export default function HostProfilePage() {
} }
return ( return (
<div className="pt-[44px] pb-16 normal-case text-[#475467]"> <div className='pb-16 pt-[44px] normal-case text-[#475467]'>
<div className="flex flex-wrap-reverse justify-between "> <div className='flex flex-wrap-reverse justify-between '>
<div className="flex max-w-3xl flex-grow flex-col justify-between md:flex-row md:items-center"> <div className='flex max-w-3xl flex-grow flex-col justify-between md:flex-row md:items-center'>
<div className="mb-[16px] flex flex-col"> <div className='mb-[16px] flex flex-col'>
<h3 className="text-xl font-semibold">Your photo</h3> <h3 className='text-xl font-semibold'>Your photo</h3>
<small className="text-xs md:text-sm">{getProfilePhotoMessage(globalState.user.is_photo_approved)}</small> <small className='text-xs md:text-sm'>
{getProfilePhotoMessage(globalState.user.is_photo_approved)}
</small>
</div> </div>
<div <div
data-tour="photo-step" data-tour='photo-step'
className="flex items-center justify-between"> className='flex items-center justify-between'
>
<img <img
src={globalState.user.photo ?? "/default.png"} src={globalState.user.photo ?? "/default.png"}
alt="" alt=''
className="h-[56px] w-[56px] rounded-full object-cover md:mr-[65px] md:h-[64px] md:w-[64px]" className='h-[56px] w-[56px] rounded-full object-cover md:mr-[65px] md:h-[64px] md:w-[64px]'
/> />
<div> <div>
<label <label
className="photo-step mr-3 cursor-pointer font-semibold underline" className='photo-step mr-3 cursor-pointer font-semibold underline'
htmlFor="profilePic" htmlFor='profilePic'
> >
Update{" "} Update{" "}
<input <input
type="file" type='file'
className="hidden" className='hidden'
id="profilePic" id='profilePic'
onChange={changeProfilePic} onChange={changeProfilePic}
/> />
</label> </label>
<button <button
className="underline" className='underline'
id="remove_profile_pic" id='remove_profile_pic'
onClick={removeProfilePic} onClick={() => {
globalDispatch({
type: "SHOW_CONFIRMATION",
payload: {
heading: "Remove Profile Picture?",
message:
"Are you sure you want to remove your profile picture?",
btn: "Yes, Remove",
onClose: () => {
removeProfilePic();
},
},
});
}}
> >
Remove Remove
</button> </button>
</div> </div>
</div> </div>
</div> </div>
<div className="mb-12 flex w-full justify-between md:mb-0 md:w-[unset] md:flex-col md:justify-start"> <div className='mb-12 flex w-full justify-between md:mb-0 md:w-[unset] md:flex-col md:justify-start'>
<p className="mb-2 self-end">Profile status</p> <p className='mb-2 self-end'>Profile status</p>
<div data-tour="fourth-step" className="flex fourth-step"> <div data-tour='fourth-step' className='fourth-step flex'>
{![0, 1].includes(globalState.user.verificationStatus) && ( {![0, 1].includes(globalState.user.verificationStatus) && (
<Link <Link
to="/account/verification" to='/account/verification'
className="mr-3 font-semibold text-[#1570EF]" className='mr-3 font-semibold text-[#1570EF]'
> >
Get verified Get verified
</Link> </Link>
@@ -215,7 +264,11 @@ export default function HostProfilePage() {
<button <button
className={ className={
`${globalState.user.verificationStatus == 1 ? "login-btn-gradient" : "bg-[#667085]"}` + `${
globalState.user.verificationStatus == 1
? "login-btn-gradient"
: "bg-[#667085]"
}` +
" flex min-w-[103px] items-center gap-1 rounded-md p-1 px-2 text-xs uppercase tracking-wider text-white" " flex min-w-[103px] items-center gap-1 rounded-md p-1 px-2 text-xs uppercase tracking-wider text-white"
} }
> >
@@ -225,28 +278,28 @@ export default function HostProfilePage() {
return ( return (
<> <>
<NotVerifiedIcon /> <NotVerifiedIcon />
<span className="">Pending</span> <span className=''>Pending</span>
</> </>
); );
case 1: case 1:
return ( return (
<> <>
<NotVerifiedIcon /> <NotVerifiedIcon />
<span className="">Verified</span> <span className=''>Verified</span>
</> </>
); );
case 2: case 2:
return ( return (
<> <>
<NotVerifiedIcon /> <NotVerifiedIcon />
<span className="">Verification Declined</span> <span className=''>Verification Declined</span>
</> </>
); );
default: default:
return ( return (
<> <>
<NotVerifiedIcon /> <NotVerifiedIcon />
<span className="">Not verified</span> <span className=''>Not verified</span>
</> </>
); );
} }
@@ -256,17 +309,17 @@ export default function HostProfilePage() {
</div> </div>
</div> </div>
<hr className="my-[37px]" /> <hr className='my-[37px]' />
<div className="grid sm:flex flex-co items-start gap-4"> <div className='flex-co grid items-start gap-4 sm:flex'>
<Link <Link
to={"/account/profile/rules-templates"} to={"/account/profile/rules-templates"}
className="rounded-md border border-primary-dark px-4 py-2 text-sm text-black duration-200 hover:bg-primary-dark hover:text-white" className='rounded-md border border-primary-dark px-4 py-2 text-sm text-black duration-200 hover:bg-primary-dark hover:text-white'
> >
Manage Property Rules Template Manage Property Rules Template
</Link> </Link>
<Link <Link
to={"/account/profile/rules-templates/add"} to={"/account/profile/rules-templates/add"}
className="rounded-md border border-primary-dark px-4 py-2 text-sm text-black duration-200 hover:bg-primary-dark hover:text-white" className='rounded-md border border-primary-dark px-4 py-2 text-sm text-black duration-200 hover:bg-primary-dark hover:text-white'
> >
Add Property Rules Template Add Property Rules Template
</Link> </Link>
@@ -299,6 +352,16 @@ export default function HostProfilePage() {
isOpen={enableEmailDialog} isOpen={enableEmailDialog}
closeModal={() => setEnableEmailDialog(false)} closeModal={() => setEnableEmailDialog(false)}
/> />
<ProfileImageConfirmModal
modalOpen={showImagePreview}
modalImage={
selectedImage instanceof File
? URL.createObjectURL(selectedImage)
: selectedImage
}
onConfirm={handleConfirmUpload}
onCancel={handleCancelUpload}
/>
</div> </div>
); );
} }