ISSUE 6: add confirmation modal before profile pic removal and preview modal on upload
This commit is contained in:
@@ -9,28 +9,45 @@ export default function ConfirmationModal() {
|
||||
if (!state.confirmation) return null;
|
||||
|
||||
return (
|
||||
<div className={"popup-container z-100 flex items-center justify-center normal-case"}>
|
||||
<div
|
||||
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`}
|
||||
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()}
|
||||
>
|
||||
<h2 className="mb-4 text-3xl font-semibold">
|
||||
<h2 className='mb-4 text-3xl font-semibold'>
|
||||
<GreenCheckIcon />
|
||||
{state.confirmationHeading}
|
||||
</h2>
|
||||
<p className="mb-4 text-sm text-gray-500">{state.confirmationMsg}</p>
|
||||
<button
|
||||
type="button"
|
||||
className="login-btn-gradient mt-4 w-full rounded py-2 tracking-wide text-white outline-none focus:outline-none"
|
||||
onClick={() => {
|
||||
if (state.confirmationCloseFn) {
|
||||
state.confirmationCloseFn();
|
||||
}
|
||||
dispatch({ type: "CLOSE_CONFIRMATION" });
|
||||
}}
|
||||
>
|
||||
{state.confirmationBtn}
|
||||
</button>
|
||||
<p className='mb-4 text-sm text-gray-500'>{state.confirmationMsg}</p>
|
||||
<div className='flex gap-4 *:w-1/2'>
|
||||
<button
|
||||
type='button'
|
||||
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={() => {
|
||||
if (state.confirmationCloseFn) {
|
||||
state.confirmationCloseFn();
|
||||
}
|
||||
dispatch({ type: "CLOSE_CONFIRMATION" });
|
||||
}}
|
||||
>
|
||||
{state.confirmationBtn}
|
||||
</button>
|
||||
</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 Skeleton from "react-loading-skeleton";
|
||||
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 TwoFaDialog from "@/components/Profile/TwoFaDialog";
|
||||
import EditProfileModal from "@/components/Profile/EditProfileModal";
|
||||
@@ -18,6 +22,7 @@ import EditAboutModal from "@/components/Profile/EditAboutModal";
|
||||
import { parseJsonSafely } from "@/utils/utils";
|
||||
import EnableEmailDialog from "@/components/Profile/EnableEmailDialog";
|
||||
import DeleteAccountModal from "@/components/Profile/DeleteAccountModal";
|
||||
import ProfileImageConfirmModal from "@/components/Profile/ProfileImageConfirmModal";
|
||||
|
||||
function getProfilePhotoMessage(image_status) {
|
||||
switch (image_status) {
|
||||
@@ -33,7 +38,8 @@ function getProfilePhotoMessage(image_status) {
|
||||
}
|
||||
|
||||
export default function CustomerProfilePage() {
|
||||
const { dispatch: globalDispatch, state: globalState } = useContext(GlobalContext);
|
||||
const { dispatch: globalDispatch, state: globalState } =
|
||||
useContext(GlobalContext);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [twoFa, setTwoFa] = useState(false);
|
||||
const [twoFaDialog, setTwoFaDialog] = useState(false);
|
||||
@@ -49,20 +55,29 @@ export default function CustomerProfilePage() {
|
||||
|
||||
const [deleteAccountModal, setDeleteAccountModal] = useState(false);
|
||||
|
||||
const [showImagePreview, setShowImagePreview] = useState(false);
|
||||
const [selectedImage, setSelectedImage] = useState(null);
|
||||
|
||||
let sdk = new MkdSDK();
|
||||
|
||||
const changeProfilePic = async (e) => {
|
||||
globalDispatch({ type: "START_LOADING" });
|
||||
const file = e.target.files;
|
||||
const formData = new FormData();
|
||||
for (let i = 0; i < file.length; i++) {
|
||||
formData.append("file", file[i]);
|
||||
const changeProfilePic = (e) => {
|
||||
const file = e.target.files && e.target.files[0];
|
||||
if (file) {
|
||||
setSelectedImage(file);
|
||||
setShowImagePreview(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleConfirmUpload = async () => {
|
||||
setShowImagePreview(false);
|
||||
if (!selectedImage) return;
|
||||
globalDispatch({ type: "START_LOADING" });
|
||||
const formData = new FormData();
|
||||
formData.append("file", selectedImage);
|
||||
try {
|
||||
const upload = await sdk.uploadImage(formData);
|
||||
console.log("upload", upload);
|
||||
sdk.setTable("user");
|
||||
const result = await callCustomAPI(
|
||||
await callCustomAPI(
|
||||
"edit-self",
|
||||
"post",
|
||||
{
|
||||
@@ -71,9 +86,16 @@ export default function CustomerProfilePage() {
|
||||
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
|
||||
sdk.setTable("notification");
|
||||
await sdk.callRestAPI(
|
||||
@@ -86,7 +108,7 @@ export default function CustomerProfilePage() {
|
||||
type: NOTIFICATION_TYPE.EDIT_USER_PICTURE,
|
||||
status: NOTIFICATION_STATUS.NOT_ADDRESSED,
|
||||
},
|
||||
"POST",
|
||||
"POST"
|
||||
);
|
||||
} catch (err) {
|
||||
globalDispatch({
|
||||
@@ -98,9 +120,15 @@ export default function CustomerProfilePage() {
|
||||
});
|
||||
}
|
||||
globalDispatch({ type: "STOP_LOADING" });
|
||||
setSelectedImage(null);
|
||||
};
|
||||
|
||||
const removeProfilePic = async (e) => {
|
||||
const handleCancelUpload = () => {
|
||||
setShowImagePreview(false);
|
||||
setSelectedImage(null);
|
||||
};
|
||||
|
||||
const removeProfilePic = async () => {
|
||||
try {
|
||||
sdk.setTable("user");
|
||||
await callCustomAPI(
|
||||
@@ -112,9 +140,12 @@ export default function CustomerProfilePage() {
|
||||
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) {
|
||||
globalDispatch({
|
||||
type: "SHOW_ERROR",
|
||||
@@ -137,14 +168,16 @@ export default function CustomerProfilePage() {
|
||||
two_factor_authentication: twoFa != 1 ? 1 : 0,
|
||||
},
|
||||
},
|
||||
"",
|
||||
""
|
||||
);
|
||||
setTwoFaDialog(false);
|
||||
globalDispatch({
|
||||
type: "SHOW_CONFIRMATION",
|
||||
payload: {
|
||||
heading: "Success",
|
||||
message: `Two factor Authentication ${twoFa == 1 ? "disabled" : "enabled"}`,
|
||||
message: `Two factor Authentication ${
|
||||
twoFa == 1 ? "disabled" : "enabled"
|
||||
}`,
|
||||
btn: "Ok got it",
|
||||
},
|
||||
});
|
||||
@@ -163,50 +196,66 @@ export default function CustomerProfilePage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="pt-[44px] pb-16 normal-case text-[#475467]">
|
||||
<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="mb-[16px] flex flex-col">
|
||||
<h3 className="text-xl font-semibold">Your photo</h3>
|
||||
<small className="text-xs md:text-sm">{getProfilePhotoMessage(globalState.user.is_photo_approved)}</small>
|
||||
<div className='pb-16 pt-[44px] normal-case text-[#475467]'>
|
||||
<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='mb-[16px] flex flex-col'>
|
||||
<h3 className='text-xl font-semibold'>Your photo</h3>
|
||||
<small className='text-xs md:text-sm'>
|
||||
{getProfilePhotoMessage(globalState.user.is_photo_approved)}
|
||||
</small>
|
||||
</div>
|
||||
<div
|
||||
data-tour="photo-step"
|
||||
className="flex items-center justify-between">
|
||||
data-tour='photo-step'
|
||||
className='flex items-center justify-between'
|
||||
>
|
||||
<img
|
||||
src={globalState.user.photo ?? "/default.png"}
|
||||
alt=""
|
||||
className="photo-step h-[56px] w-[56px] rounded-full object-cover md:mr-[65px] md:h-[64px] md:w-[64px]"
|
||||
alt=''
|
||||
className='photo-step h-[56px] w-[56px] rounded-full object-cover md:mr-[65px] md:h-[64px] md:w-[64px]'
|
||||
/>
|
||||
<div>
|
||||
<label
|
||||
className="third-step mr-3 cursor-pointer font-semibold underline"
|
||||
htmlFor="profilePic"
|
||||
className='third-step mr-3 cursor-pointer font-semibold underline'
|
||||
htmlFor='profilePic'
|
||||
>
|
||||
Update{" "}
|
||||
<input
|
||||
type="file"
|
||||
className="hidden"
|
||||
id="profilePic"
|
||||
type='file'
|
||||
className='hidden'
|
||||
id='profilePic'
|
||||
onChange={changeProfilePic}
|
||||
/>
|
||||
</label>
|
||||
<button
|
||||
className="underline"
|
||||
onClick={removeProfilePic}
|
||||
className='underline'
|
||||
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
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div data-tour="fourth-step" className="flex fourth-step">
|
||||
<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>
|
||||
<div data-tour='fourth-step' className='fourth-step flex'>
|
||||
{![0, 1].includes(globalState.user.verificationStatus) && (
|
||||
<Link
|
||||
to="/account/verification"
|
||||
className="mr-3 font-semibold text-[#1570EF]"
|
||||
to='/account/verification'
|
||||
className='mr-3 font-semibold text-[#1570EF]'
|
||||
>
|
||||
Get verified
|
||||
</Link>
|
||||
@@ -214,7 +263,11 @@ export default function CustomerProfilePage() {
|
||||
|
||||
<button
|
||||
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"
|
||||
}
|
||||
>
|
||||
@@ -255,7 +308,7 @@ export default function CustomerProfilePage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr className="my-[37px]" />
|
||||
<hr className='my-[37px]' />
|
||||
<EditProfileModal
|
||||
closeModal={() => setUpdateName(false)}
|
||||
modalOpen={updateName}
|
||||
@@ -284,6 +337,16 @@ export default function CustomerProfilePage() {
|
||||
isOpen={enableEmailDialog}
|
||||
closeModal={() => setEnableEmailDialog(false)}
|
||||
/>
|
||||
<ProfileImageConfirmModal
|
||||
modalOpen={showImagePreview}
|
||||
modalImage={
|
||||
selectedImage instanceof File
|
||||
? URL.createObjectURL(selectedImage)
|
||||
: selectedImage
|
||||
}
|
||||
onConfirm={handleConfirmUpload}
|
||||
onCancel={handleCancelUpload}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,11 @@ import MkdSDK from "@/utils/MkdSDK";
|
||||
import { callCustomAPI } from "@/utils/callCustomAPI";
|
||||
import Skeleton from "react-loading-skeleton";
|
||||
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 TwoFaDialog from "@/components/Profile/TwoFaDialog";
|
||||
import EditProfileModal from "@/components/Profile/EditProfileModal";
|
||||
@@ -18,6 +22,7 @@ import EditAboutModal from "@/components/Profile/EditAboutModal";
|
||||
import { parseJsonSafely } from "@/utils/utils";
|
||||
import EnableEmailDialog from "@/components/Profile/EnableEmailDialog";
|
||||
import DeleteAccountModal from "@/components/Profile/DeleteAccountModal";
|
||||
import ProfileImageConfirmModal from "@/components/Profile/ProfileImageConfirmModal";
|
||||
|
||||
function getProfilePhotoMessage(image_status) {
|
||||
switch (image_status) {
|
||||
@@ -33,7 +38,8 @@ function getProfilePhotoMessage(image_status) {
|
||||
}
|
||||
|
||||
export default function HostProfilePage() {
|
||||
const { dispatch: globalDispatch, state: globalState } = useContext(GlobalContext);
|
||||
const { dispatch: globalDispatch, state: globalState } =
|
||||
useContext(GlobalContext);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [twoFa, setTwoFa] = useState(false);
|
||||
const [twoFaDialog, setTwoFaDialog] = useState(false);
|
||||
@@ -49,20 +55,29 @@ export default function HostProfilePage() {
|
||||
|
||||
const [deleteAccountModal, setDeleteAccountModal] = useState(false);
|
||||
|
||||
const [showImagePreview, setShowImagePreview] = useState(false);
|
||||
const [selectedImage, setSelectedImage] = useState(null);
|
||||
|
||||
let sdk = new MkdSDK();
|
||||
|
||||
const changeProfilePic = async (e) => {
|
||||
globalDispatch({ type: "START_LOADING" });
|
||||
const file = e.target.files;
|
||||
const formData = new FormData();
|
||||
for (let i = 0; i < file.length; i++) {
|
||||
formData.append("file", file[i]);
|
||||
const changeProfilePic = (e) => {
|
||||
const file = e.target.files && e.target.files[0];
|
||||
if (file) {
|
||||
setSelectedImage(file);
|
||||
setShowImagePreview(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleConfirmUpload = async () => {
|
||||
setShowImagePreview(false);
|
||||
if (!selectedImage) return;
|
||||
globalDispatch({ type: "START_LOADING" });
|
||||
const formData = new FormData();
|
||||
formData.append("file", selectedImage);
|
||||
try {
|
||||
const upload = await sdk.uploadImage(formData);
|
||||
console.log("upload", upload);
|
||||
sdk.setTable("user");
|
||||
const result = await callCustomAPI(
|
||||
await callCustomAPI(
|
||||
"edit-self",
|
||||
"post",
|
||||
{
|
||||
@@ -71,9 +86,16 @@ export default function HostProfilePage() {
|
||||
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
|
||||
sdk.setTable("notification");
|
||||
await sdk.callRestAPI(
|
||||
@@ -86,7 +108,7 @@ export default function HostProfilePage() {
|
||||
type: NOTIFICATION_TYPE.EDIT_USER_PICTURE,
|
||||
status: NOTIFICATION_STATUS.NOT_ADDRESSED,
|
||||
},
|
||||
"POST",
|
||||
"POST"
|
||||
);
|
||||
} catch (err) {
|
||||
globalDispatch({
|
||||
@@ -98,9 +120,15 @@ export default function HostProfilePage() {
|
||||
});
|
||||
}
|
||||
globalDispatch({ type: "STOP_LOADING" });
|
||||
setSelectedImage(null);
|
||||
};
|
||||
|
||||
const removeProfilePic = async (e) => {
|
||||
const handleCancelUpload = () => {
|
||||
setShowImagePreview(false);
|
||||
setSelectedImage(null);
|
||||
};
|
||||
|
||||
const removeProfilePic = async () => {
|
||||
try {
|
||||
sdk.setTable("user");
|
||||
await callCustomAPI(
|
||||
@@ -112,9 +140,12 @@ export default function HostProfilePage() {
|
||||
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) {
|
||||
globalDispatch({
|
||||
type: "SHOW_ERROR",
|
||||
@@ -137,14 +168,16 @@ export default function HostProfilePage() {
|
||||
two_factor_authentication: twoFa != 1 ? 1 : 0,
|
||||
},
|
||||
},
|
||||
"",
|
||||
""
|
||||
);
|
||||
setTwoFaDialog(false);
|
||||
globalDispatch({
|
||||
type: "SHOW_CONFIRMATION",
|
||||
payload: {
|
||||
heading: "Success",
|
||||
message: `Two factor Authentication ${twoFa == 1 ? "disabled" : "enabled"}`,
|
||||
message: `Two factor Authentication ${
|
||||
twoFa == 1 ? "disabled" : "enabled"
|
||||
}`,
|
||||
btn: "Ok got it",
|
||||
},
|
||||
});
|
||||
@@ -163,51 +196,67 @@ export default function HostProfilePage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="pt-[44px] pb-16 normal-case text-[#475467]">
|
||||
<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="mb-[16px] flex flex-col">
|
||||
<h3 className="text-xl font-semibold">Your photo</h3>
|
||||
<small className="text-xs md:text-sm">{getProfilePhotoMessage(globalState.user.is_photo_approved)}</small>
|
||||
<div className='pb-16 pt-[44px] normal-case text-[#475467]'>
|
||||
<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='mb-[16px] flex flex-col'>
|
||||
<h3 className='text-xl font-semibold'>Your photo</h3>
|
||||
<small className='text-xs md:text-sm'>
|
||||
{getProfilePhotoMessage(globalState.user.is_photo_approved)}
|
||||
</small>
|
||||
</div>
|
||||
<div
|
||||
data-tour="photo-step"
|
||||
className="flex items-center justify-between">
|
||||
data-tour='photo-step'
|
||||
className='flex items-center justify-between'
|
||||
>
|
||||
<img
|
||||
src={globalState.user.photo ?? "/default.png"}
|
||||
alt=""
|
||||
className="h-[56px] w-[56px] rounded-full object-cover md:mr-[65px] md:h-[64px] md:w-[64px]"
|
||||
alt=''
|
||||
className='h-[56px] w-[56px] rounded-full object-cover md:mr-[65px] md:h-[64px] md:w-[64px]'
|
||||
/>
|
||||
<div>
|
||||
<label
|
||||
className="photo-step mr-3 cursor-pointer font-semibold underline"
|
||||
htmlFor="profilePic"
|
||||
className='photo-step mr-3 cursor-pointer font-semibold underline'
|
||||
htmlFor='profilePic'
|
||||
>
|
||||
Update{" "}
|
||||
<input
|
||||
type="file"
|
||||
className="hidden"
|
||||
id="profilePic"
|
||||
type='file'
|
||||
className='hidden'
|
||||
id='profilePic'
|
||||
onChange={changeProfilePic}
|
||||
/>
|
||||
</label>
|
||||
<button
|
||||
className="underline"
|
||||
id="remove_profile_pic"
|
||||
onClick={removeProfilePic}
|
||||
className='underline'
|
||||
id='remove_profile_pic'
|
||||
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
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div data-tour="fourth-step" className="flex fourth-step">
|
||||
<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>
|
||||
<div data-tour='fourth-step' className='fourth-step flex'>
|
||||
{![0, 1].includes(globalState.user.verificationStatus) && (
|
||||
<Link
|
||||
to="/account/verification"
|
||||
className="mr-3 font-semibold text-[#1570EF]"
|
||||
to='/account/verification'
|
||||
className='mr-3 font-semibold text-[#1570EF]'
|
||||
>
|
||||
Get verified
|
||||
</Link>
|
||||
@@ -215,7 +264,11 @@ export default function HostProfilePage() {
|
||||
|
||||
<button
|
||||
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"
|
||||
}
|
||||
>
|
||||
@@ -225,28 +278,28 @@ export default function HostProfilePage() {
|
||||
return (
|
||||
<>
|
||||
<NotVerifiedIcon />
|
||||
<span className="">Pending</span>
|
||||
<span className=''>Pending</span>
|
||||
</>
|
||||
);
|
||||
case 1:
|
||||
return (
|
||||
<>
|
||||
<NotVerifiedIcon />
|
||||
<span className="">Verified</span>
|
||||
<span className=''>Verified</span>
|
||||
</>
|
||||
);
|
||||
case 2:
|
||||
return (
|
||||
<>
|
||||
<NotVerifiedIcon />
|
||||
<span className="">Verification Declined</span>
|
||||
<span className=''>Verification Declined</span>
|
||||
</>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<>
|
||||
<NotVerifiedIcon />
|
||||
<span className="">Not verified</span>
|
||||
<span className=''>Not verified</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -256,17 +309,17 @@ export default function HostProfilePage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr className="my-[37px]" />
|
||||
<div className="grid sm:flex flex-co items-start gap-4">
|
||||
<hr className='my-[37px]' />
|
||||
<div className='flex-co grid items-start gap-4 sm:flex'>
|
||||
<Link
|
||||
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
|
||||
</Link>
|
||||
<Link
|
||||
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
|
||||
</Link>
|
||||
@@ -299,6 +352,16 @@ export default function HostProfilePage() {
|
||||
isOpen={enableEmailDialog}
|
||||
closeModal={() => setEnableEmailDialog(false)}
|
||||
/>
|
||||
<ProfileImageConfirmModal
|
||||
modalOpen={showImagePreview}
|
||||
modalImage={
|
||||
selectedImage instanceof File
|
||||
? URL.createObjectURL(selectedImage)
|
||||
: selectedImage
|
||||
}
|
||||
onConfirm={handleConfirmUpload}
|
||||
onCancel={handleCancelUpload}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user