Merge pull request 'feat(profile): display dynamic user data from context' (#43) from profile-view into develop
Reviewed-on: https://repo.ravanertebat.com/TM/tm_panel/pulls/43
This commit is contained in:
+101
-124
@@ -1,148 +1,125 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { CheckIcon, CrossIcon, UserIcon } from "@/assets/icons";
|
||||||
|
import Status from "@/components/ui/Status";
|
||||||
|
import { useUser } from "@/contexts";
|
||||||
|
import { formatPhoneNumber, unixToDate } from "@/utils/shared";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { CameraIcon } from "./_components/icons";
|
|
||||||
import { SocialAccounts } from "./_components/social-accounts";
|
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const [data, setData] = useState({
|
const { user: data } = useUser();
|
||||||
name: "Danish Heilium",
|
const [imageError, setImageError] = useState(false);
|
||||||
profilePhoto: "/images/user/user-03.png",
|
|
||||||
coverPhoto: "/images/cover/cover-01.png",
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleChange = (e: any) => {
|
const hasProfileImage = data?.profile_image && !imageError;
|
||||||
if (e.target.name === "profilePhoto") {
|
|
||||||
const file = e.target?.files[0];
|
|
||||||
|
|
||||||
setData({
|
|
||||||
...data,
|
|
||||||
profilePhoto: file && URL.createObjectURL(file),
|
|
||||||
});
|
|
||||||
} else if (e.target.name === "coverPhoto") {
|
|
||||||
const file = e.target?.files[0];
|
|
||||||
|
|
||||||
setData({
|
|
||||||
...data,
|
|
||||||
coverPhoto: file && URL.createObjectURL(file),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
setData({
|
|
||||||
...data,
|
|
||||||
[e.target.name]: e.target.value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto w-full max-w-[970px]">
|
<div className="mx-auto w-full max-w-4xl rounded-lg bg-white p-6 shadow-default dark:bg-gray-dark">
|
||||||
<div className="overflow-hidden rounded-[10px] bg-white shadow-1 dark:bg-gray-dark dark:shadow-card">
|
<div className="relative h-48 w-full rounded-t-lg bg-gray-200 dark:bg-gray-700">
|
||||||
<div className="relative z-20 h-35 md:h-65">
|
|
||||||
<Image
|
<Image
|
||||||
src={data?.coverPhoto}
|
src={"/images/cover/cover-01.png"}
|
||||||
alt="profile cover"
|
alt="Cover"
|
||||||
className="h-full w-full rounded-tl-[10px] rounded-tr-[10px] object-cover object-center"
|
layout="fill"
|
||||||
width={970}
|
objectFit="cover"
|
||||||
height={260}
|
className="rounded-t-lg"
|
||||||
style={{
|
|
||||||
width: "auto",
|
|
||||||
height: "auto",
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<div className="absolute bottom-1 right-1 z-10 xsm:bottom-4 xsm:right-4">
|
<div className="absolute bottom-0 left-1/2 -translate-x-1/2 translate-y-1/2 transform">
|
||||||
<label
|
<div className="relative flex h-32 w-32 items-center justify-center overflow-hidden rounded-full border-4 border-white bg-gray-200 dark:border-gray-dark dark:bg-gray-700">
|
||||||
htmlFor="cover"
|
{hasProfileImage ? (
|
||||||
className="flex cursor-pointer items-center justify-center gap-2 rounded-lg bg-primary px-[15px] py-[5px] text-body-sm font-medium text-white hover:bg-opacity-90"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="file"
|
|
||||||
name="coverPhoto"
|
|
||||||
id="coverPhoto"
|
|
||||||
className="sr-only"
|
|
||||||
onChange={handleChange}
|
|
||||||
accept="image/png, image/jpg, image/jpeg"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<CameraIcon />
|
|
||||||
|
|
||||||
<span>Edit</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="px-4 pb-6 text-center lg:pb-8 xl:pb-11.5">
|
|
||||||
<div className="relative z-30 mx-auto -mt-22 h-30 w-full max-w-30 rounded-full bg-white/20 p-1 backdrop-blur sm:h-44 sm:max-w-[176px] sm:p-3">
|
|
||||||
<div className="relative drop-shadow-2">
|
|
||||||
{data?.profilePhoto && (
|
|
||||||
<>
|
|
||||||
<Image
|
<Image
|
||||||
src={data?.profilePhoto}
|
onError={() => setImageError(true)}
|
||||||
width={160}
|
alt="Profile"
|
||||||
height={160}
|
src={data.profile_image!}
|
||||||
className="overflow-hidden rounded-full"
|
layout="fill"
|
||||||
alt="profile"
|
objectFit="cover"
|
||||||
|
className="rounded-full"
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
<label
|
<UserIcon className="h-16 w-16 text-gray-400 dark:text-gray-500" />
|
||||||
htmlFor="profilePhoto"
|
|
||||||
className="absolute bottom-0 right-0 flex size-8.5 cursor-pointer items-center justify-center rounded-full bg-primary text-white hover:bg-opacity-90 sm:bottom-2 sm:right-2"
|
|
||||||
>
|
|
||||||
<CameraIcon />
|
|
||||||
|
|
||||||
<input
|
|
||||||
type="file"
|
|
||||||
name="profilePhoto"
|
|
||||||
id="profilePhoto"
|
|
||||||
className="sr-only"
|
|
||||||
onChange={handleChange}
|
|
||||||
accept="image/png, image/jpg, image/jpeg"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-4">
|
|
||||||
<h3 className="mb-1 text-heading-6 font-bold text-dark dark:text-white">
|
|
||||||
{data?.name}
|
|
||||||
</h3>
|
|
||||||
<p className="font-medium">Ui/Ux Designer</p>
|
|
||||||
<div className="mx-auto mb-5.5 mt-5 grid max-w-[370px] grid-cols-3 rounded-[5px] border border-stroke py-[9px] shadow-1 dark:border-dark-3 dark:bg-dark-2 dark:shadow-card">
|
|
||||||
<div className="flex flex-col items-center justify-center gap-1 border-r border-stroke px-4 dark:border-dark-3 xsm:flex-row">
|
|
||||||
<span className="font-medium text-dark dark:text-white">
|
|
||||||
259
|
|
||||||
</span>
|
|
||||||
<span className="text-body-sm">Posts</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-col items-center justify-center gap-1 border-r border-stroke px-4 dark:border-dark-3 xsm:flex-row">
|
|
||||||
<span className="font-medium text-dark dark:text-white">
|
|
||||||
129K
|
|
||||||
</span>
|
|
||||||
<span className="text-body-sm">Followers</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-col items-center justify-center gap-1 px-4 xsm:flex-row">
|
|
||||||
<span className="font-medium text-dark dark:text-white">
|
|
||||||
2K
|
|
||||||
</span>
|
|
||||||
<span className="text-body-sm-sm">Following</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mx-auto max-w-[720px]">
|
<div className="mt-16 text-center">
|
||||||
<h4 className="font-medium text-dark dark:text-white">
|
<h1 className="text-2xl font-bold text-dark dark:text-white">
|
||||||
About Me
|
{data?.full_name}
|
||||||
</h4>
|
</h1>
|
||||||
<p className="mt-4">
|
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
@{data?.username}
|
||||||
Pellentesque posuere fermentum urna, eu condimentum mauris
|
|
||||||
tempus ut. Donec fermentum blandit aliquet. Etiam dictum dapibus
|
|
||||||
ultricies. Sed vel aliquet libero. Nunc a augue fermentum,
|
|
||||||
pharetra ligula sed, aliquam lacus.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SocialAccounts />
|
<div className="mt-6 border-t border-stroke pt-6 dark:border-stroke-dark">
|
||||||
|
<h2 className="mb-4 text-lg font-semibold text-dark dark:text-white">
|
||||||
|
User Information
|
||||||
|
</h2>
|
||||||
|
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||||
|
<div>
|
||||||
|
<p className="font-medium text-dark dark:text-white">Email</p>
|
||||||
|
<p className="text-gray-600 dark:text-gray-300">{data?.email}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="font-medium text-dark dark:text-white">Phone</p>
|
||||||
|
<p className="text-gray-600 dark:text-gray-300">
|
||||||
|
{formatPhoneNumber(data?.phone)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="font-medium text-dark dark:text-white">Department</p>
|
||||||
|
<p className="text-gray-600 dark:text-gray-300">
|
||||||
|
{data?.department}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="font-medium text-dark dark:text-white">Position</p>
|
||||||
|
<p className="text-gray-600 dark:text-gray-300">{data?.position}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="font-medium text-dark dark:text-white">Role</p>
|
||||||
|
<p className="capitalize text-gray-600 dark:text-gray-300">
|
||||||
|
{data?.role}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="font-medium text-dark dark:text-white">Status</p>
|
||||||
|
<div className="w-fit">
|
||||||
|
<Status status={data?.status}>{data?.status}</Status>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-6 border-t border-stroke pt-6 dark:border-stroke-dark">
|
||||||
|
<h2 className="mb-4 text-lg font-semibold text-dark dark:text-white">
|
||||||
|
Account Details
|
||||||
|
</h2>
|
||||||
|
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||||
|
<div>
|
||||||
|
<p className="font-medium text-dark dark:text-white">Verified</p>
|
||||||
|
<div className="w-fit">
|
||||||
|
<Status status={data?.is_verified ? "success" : "warning"}>
|
||||||
|
{data?.is_verified ? (
|
||||||
|
<CheckIcon fill="green" width={20} height={20} />
|
||||||
|
) : (
|
||||||
|
<CrossIcon fill="red" width={20} />
|
||||||
|
)}
|
||||||
|
</Status>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="font-medium text-dark dark:text-white">Last Login</p>
|
||||||
|
<p className="text-gray-600 dark:text-gray-300">
|
||||||
|
{unixToDate({ unix: data?.last_login_at ?? 0, hasTime: true })}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="font-medium text-dark dark:text-white">
|
||||||
|
Member Since
|
||||||
|
</p>
|
||||||
|
<p className="text-gray-600 dark:text-gray-300">
|
||||||
|
{unixToDate({ unix: data?.created_at ?? 0, hasTime: true })}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export function TextAreaGroup<T extends FieldValues>({
|
|||||||
className="mb-3 block text-body-sm font-medium text-dark dark:text-white"
|
className="mb-3 block text-body-sm font-medium text-dark dark:text-white"
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
{required && <span className="text-red ml-1 select-none">*</span>}
|
{required && <span className="ml-1 select-none text-error">*</span>}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div className="relative mt-3 [&_svg]:pointer-events-none [&_svg]:absolute [&_svg]:left-5.5 [&_svg]:top-5.5">
|
<div className="relative mt-3 [&_svg]:pointer-events-none [&_svg]:absolute [&_svg]:left-5.5 [&_svg]:top-5.5">
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ export function Notification() {
|
|||||||
setCurrentNotification(notification);
|
setCurrentNotification(notification);
|
||||||
setIsModalOpen(true);
|
setIsModalOpen(true);
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
|
mutate();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -95,15 +96,13 @@ export function Notification() {
|
|||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
isOpen={isModalOpen}
|
isOpen={isModalOpen}
|
||||||
|
showButtons={false}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
setIsModalOpen(false);
|
setIsModalOpen(false);
|
||||||
}}
|
}}
|
||||||
confirmText="Mark as read"
|
confirmText="Mark as read"
|
||||||
onConfirm={() => {
|
|
||||||
mutate();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div className="flex flex-col gap-3 max-w-prose">
|
<div className="flex max-w-prose flex-col gap-3">
|
||||||
<h2 className="font-lg font-bold">{currentNotification?.title}</h2>
|
<h2 className="font-lg font-bold">{currentNotification?.title}</h2>
|
||||||
<p>{currentNotification?.message}</p>
|
<p>{currentNotification?.message}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ const NotificationList = ({
|
|||||||
key={notification.id}
|
key={notification.id}
|
||||||
onClick={() => onNotificationClick(notification)}
|
onClick={() => onNotificationClick(notification)}
|
||||||
>
|
>
|
||||||
<div className="cursor-pointer rounded-lg px-1 py-2 hover:bg-gray-2">
|
<div className="cursor-pointer rounded-lg px-1 py-2 transition-all duration-300 hover:bg-gray-2 dark:hover:bg-gray-7">
|
||||||
<strong className="block text-lg font-medium capitalize text-dark dark:text-white">
|
<strong className="block text-lg font-medium capitalize text-dark dark:text-white">
|
||||||
{notification.title}
|
{notification.title}
|
||||||
</strong>
|
</strong>
|
||||||
|
|||||||
@@ -16,11 +16,6 @@ import { LogOutIcon, SettingsIcon, UserIcon } from "./icons";
|
|||||||
export function UserInfo() {
|
export function UserInfo() {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const { logout, user } = useUser();
|
const { logout, user } = useUser();
|
||||||
const USER = {
|
|
||||||
name: "John Smith",
|
|
||||||
email: "johnson@nextadmin.com",
|
|
||||||
img: "/images/user/user-03.png",
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown isOpen={isOpen} setIsOpen={setIsOpen}>
|
<Dropdown isOpen={isOpen} setIsOpen={setIsOpen}>
|
||||||
@@ -31,14 +26,7 @@ export function UserInfo() {
|
|||||||
<div className="rounded-full bg-gray-3 p-3.5 dark:bg-dark-3">
|
<div className="rounded-full bg-gray-3 p-3.5 dark:bg-dark-3">
|
||||||
<UserIcon />
|
<UserIcon />
|
||||||
</div>
|
</div>
|
||||||
{/* <Image
|
|
||||||
src={USER.img}
|
|
||||||
className="size-12"
|
|
||||||
alt={`Avatar of ${USER.name}`}
|
|
||||||
role="presentation"
|
|
||||||
width={200}
|
|
||||||
height={200}
|
|
||||||
/> */}
|
|
||||||
<figcaption className="flex items-center gap-1 font-medium text-dark dark:text-dark-6 max-[1024px]:sr-only">
|
<figcaption className="flex items-center gap-1 font-medium text-dark dark:text-dark-6 max-[1024px]:sr-only">
|
||||||
<span>{user?.full_name}</span>
|
<span>{user?.full_name}</span>
|
||||||
|
|
||||||
@@ -61,21 +49,27 @@ export function UserInfo() {
|
|||||||
<h2 className="sr-only">User information</h2>
|
<h2 className="sr-only">User information</h2>
|
||||||
|
|
||||||
<figure className="flex items-center gap-2.5 px-5 py-3.5">
|
<figure className="flex items-center gap-2.5 px-5 py-3.5">
|
||||||
|
{user?.profile_image ? (
|
||||||
<Image
|
<Image
|
||||||
src={USER.img}
|
src={user.profile_image}
|
||||||
className="size-12"
|
className="size-12"
|
||||||
alt={`Avatar for ${USER.name}`}
|
alt={`Avatar for ${user.full_name}`}
|
||||||
role="presentation"
|
role="presentation"
|
||||||
width={200}
|
width={200}
|
||||||
height={200}
|
height={200}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="rounded-full bg-gray-3 p-4 dark:bg-gray-7">
|
||||||
|
<UserIcon width={30} height={30} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<figcaption className="space-y-1 text-base font-medium">
|
<figcaption className="space-y-1 text-base font-medium">
|
||||||
<div className="mb-2 leading-none text-dark dark:text-white">
|
<div className="mb-2 leading-none text-dark dark:text-white">
|
||||||
{USER.name}
|
{user?.full_name}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="leading-none text-gray-6">{USER.email}</div>
|
<div className="leading-none text-gray-6">{user?.email}</div>
|
||||||
</figcaption>
|
</figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { CheckIcon, CrossIcon, EyeIcon } from "@/assets/icons";
|
import { EyeIcon } from "@/assets/icons";
|
||||||
import { ShowcaseSection } from "@/components/Layouts/showcase-section";
|
import { ShowcaseSection } from "@/components/Layouts/showcase-section";
|
||||||
import Pagination from "@/components/ui/pagination";
|
import Pagination from "@/components/ui/pagination";
|
||||||
import Status from "@/components/ui/Status";
|
import Status from "@/components/ui/Status";
|
||||||
@@ -13,9 +13,11 @@ import {
|
|||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import TableSkeleton from "@/components/ui/TableSkeleton";
|
import TableSkeleton from "@/components/ui/TableSkeleton";
|
||||||
import { _TooltipDefaultParams } from "@/constants/tooltip";
|
import { _TooltipDefaultParams } from "@/constants/tooltip";
|
||||||
import { unixToDate } from "@/utils/shared";
|
import { truncateString, unixToDate } from "@/utils/shared";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { Tooltip } from "react-tooltip";
|
import { Tooltip } from "react-tooltip";
|
||||||
|
|
||||||
|
import Boolean from "@/components/ui/Boolean";
|
||||||
import useNotificationHistoryTablePresenter from "./useNotificationHistoryTablePresenter";
|
import useNotificationHistoryTablePresenter from "./useNotificationHistoryTablePresenter";
|
||||||
|
|
||||||
const NotificationHistoryTable = () => {
|
const NotificationHistoryTable = () => {
|
||||||
@@ -64,7 +66,9 @@ const NotificationHistoryTable = () => {
|
|||||||
unix: item.created_at,
|
unix: item.created_at,
|
||||||
})}
|
})}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell colSpan={100}>{item.message}</TableCell>
|
<TableCell colSpan={100} className="truncate">
|
||||||
|
{truncateString(item.message, 20, 20)}
|
||||||
|
</TableCell>
|
||||||
<TableCell className="capitalize" colSpan={100}>
|
<TableCell className="capitalize" colSpan={100}>
|
||||||
{item.priority}
|
{item.priority}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
@@ -72,11 +76,7 @@ const NotificationHistoryTable = () => {
|
|||||||
{item.type}
|
{item.type}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="capitalize" colSpan={100}>
|
<TableCell className="capitalize" colSpan={100}>
|
||||||
{item.seen ? (
|
<Boolean value={item.seen} />
|
||||||
<CheckIcon fill="green" width={15} height={15} />
|
|
||||||
) : (
|
|
||||||
<CrossIcon width={20} fill="red" />
|
|
||||||
)}
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell colSpan={100}>
|
<TableCell colSpan={100}>
|
||||||
<Status status={item.status}>{item.status}</Status>
|
<Status status={item.status}>{item.status}</Status>
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { CheckIcon, CrossIcon } from "@/assets/icons";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
value: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Boolean = ({ value }: IProps) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{value ? (
|
||||||
|
<CheckIcon fill="green" width={15} height={15} />
|
||||||
|
) : (
|
||||||
|
<CrossIcon width={20} fill="red" />
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Boolean;
|
||||||
@@ -2,11 +2,11 @@ import { cn } from "@/lib/utils";
|
|||||||
import { ReactNode } from "react";
|
import { ReactNode } from "react";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
status: string;
|
status?: string;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Status = ({ status, children }: IProps) => {
|
const Status = ({ status = "draft", children }: IProps) => {
|
||||||
const reds = [
|
const reds = [
|
||||||
"cancelled",
|
"cancelled",
|
||||||
"inactive",
|
"inactive",
|
||||||
@@ -22,7 +22,7 @@ const Status = ({ status, children }: IProps) => {
|
|||||||
"success",
|
"success",
|
||||||
"verified",
|
"verified",
|
||||||
"published",
|
"published",
|
||||||
"sent"
|
"sent",
|
||||||
];
|
];
|
||||||
const blues = ["awarded", "processing", "in-review", "scheduled"];
|
const blues = ["awarded", "processing", "in-review", "scheduled"];
|
||||||
const yellows = ["pending", "warning", "on-hold", "delayed"];
|
const yellows = ["pending", "warning", "on-hold", "delayed"];
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { CrossIcon } from "@/assets/icons";
|
|||||||
import { useIsMutating } from "@tanstack/react-query";
|
import { useIsMutating } from "@tanstack/react-query";
|
||||||
import { ReactNode, useEffect, useState } from "react";
|
import { ReactNode, useEffect, useState } from "react";
|
||||||
import { createPortal } from "react-dom";
|
import { createPortal } from "react-dom";
|
||||||
|
import IsVisible from "./IsVisible";
|
||||||
|
|
||||||
interface ModalProps {
|
interface ModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@@ -10,6 +11,7 @@ interface ModalProps {
|
|||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
confirmText?: string;
|
confirmText?: string;
|
||||||
cancelText?: string;
|
cancelText?: string;
|
||||||
|
showButtons?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Modal: React.FC<ModalProps> = ({
|
const Modal: React.FC<ModalProps> = ({
|
||||||
@@ -19,6 +21,7 @@ const Modal: React.FC<ModalProps> = ({
|
|||||||
onConfirm,
|
onConfirm,
|
||||||
confirmText = "confirm",
|
confirmText = "confirm",
|
||||||
cancelText = "close",
|
cancelText = "close",
|
||||||
|
showButtons = true,
|
||||||
}) => {
|
}) => {
|
||||||
const [mounted, setMounted] = useState(false);
|
const [mounted, setMounted] = useState(false);
|
||||||
const isMutating = useIsMutating();
|
const isMutating = useIsMutating();
|
||||||
@@ -57,6 +60,7 @@ const Modal: React.FC<ModalProps> = ({
|
|||||||
</button>
|
</button>
|
||||||
<div className="clear-both">{children}</div>
|
<div className="clear-both">{children}</div>
|
||||||
<div className="flex gap-5">
|
<div className="flex gap-5">
|
||||||
|
<IsVisible condition={showButtons}>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="mt-6 flex w-fit justify-center rounded-lg bg-primary p-[13px] font-medium capitalize text-white hover:bg-opacity-90"
|
className="mt-6 flex w-fit justify-center rounded-lg bg-primary p-[13px] font-medium capitalize text-white hover:bg-opacity-90"
|
||||||
@@ -75,6 +79,7 @@ const Modal: React.FC<ModalProps> = ({
|
|||||||
>
|
>
|
||||||
{cancelText}
|
{cancelText}
|
||||||
</button>
|
</button>
|
||||||
|
</IsVisible>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+8
-2
@@ -53,6 +53,12 @@
|
|||||||
.rmdp-calendar {
|
.rmdp-calendar {
|
||||||
@apply !p-6 dark:!bg-gray-dark;
|
@apply !p-6 dark:!bg-gray-dark;
|
||||||
}
|
}
|
||||||
|
.rmdp-time-picker {
|
||||||
|
@apply dark:!bg-gray-dark;
|
||||||
|
}
|
||||||
|
.rmdp-time-picker div input {
|
||||||
|
@apply dark:!bg-gray-dark dark:!text-gray-5;
|
||||||
|
}
|
||||||
.rmdp-month-picker {
|
.rmdp-month-picker {
|
||||||
@apply dark:!bg-gray-dark;
|
@apply dark:!bg-gray-dark;
|
||||||
}
|
}
|
||||||
@@ -95,10 +101,10 @@
|
|||||||
color: inherit !important;
|
color: inherit !important;
|
||||||
}
|
}
|
||||||
.rmdp-day.rmdp-range.start {
|
.rmdp-day.rmdp-range.start {
|
||||||
@apply !bg-gray-2 !shadow-none dark:!bg-dark-2 !text-white;
|
@apply !bg-gray-2 !text-white !shadow-none dark:!bg-dark-2;
|
||||||
}
|
}
|
||||||
.rmdp-day.rmdp-range.end {
|
.rmdp-day.rmdp-range.end {
|
||||||
@apply !bg-gray-2 !shadow-none dark:!bg-dark-2 !text-white;
|
@apply !bg-gray-2 !text-white !shadow-none dark:!bg-dark-2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rmdp-day.rmdp-range.start,
|
.rmdp-day.rmdp-range.start,
|
||||||
|
|||||||
Reference in New Issue
Block a user