refactor: remove unused components and files related to date filtering and doctor search
- Deleted Date.js and FilterDate.js components as they are no longer needed. - Removed SearchDoctor.js component which was responsible for searching doctors. - Cleaned up the Head component by removing references to the deleted Date and SearchDoctor components. - Removed TurnsPage component and its associated List component, which were not utilized. - Deleted Cards and Table components from the list directory as they were not in use. - Removed user account related components including Tab, Head, and Form components. - Cleaned up bank account components including List, Item, and modal components. - Removed representation adapters and related functions that were not in use.
This commit is contained in:
+1
-4
@@ -1,14 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { ThemeProvider } from "next-themes";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
import Cookies from "js-cookie";
|
||||
import { setAccessToken } from "@/lib/tokenStore";
|
||||
|
||||
export function Providers({ children }) {
|
||||
const router = usePathname();
|
||||
|
||||
useEffect(() => {
|
||||
if (!Cookies.get("userInfo")) return;
|
||||
fetch("/api/auth/refresh", { method: "POST" })
|
||||
@@ -21,7 +18,7 @@ export function Providers({ children }) {
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
attribute={router.includes("/panel") ? "class" : "data-"}
|
||||
attribute="data-"
|
||||
defaultTheme="system"
|
||||
enableSystem
|
||||
>
|
||||
|
||||
@@ -1,34 +1,18 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState } from "react";
|
||||
import ProfilePA from "@/components/icons/ProfilePA";
|
||||
import LogoutP from "@/components/icons/LogoutP";
|
||||
import CardDA from "@/components/icons/CardDA";
|
||||
import { Button, Popover } from "@mui/material";
|
||||
import Link from "next/link";
|
||||
import ModalLogout from "./ModalLogout";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
function DetailProfile({ anchorEl, setAnchorEl }) {
|
||||
const [modal, setModal] = useState(false);
|
||||
const [hasRepresentationRole, setHasRepresentationRole] = useState(false);
|
||||
|
||||
const handleClose = () => setAnchorEl(null);
|
||||
const closeModal = () => setModal(false);
|
||||
const openModal = () => setModal(true);
|
||||
|
||||
useEffect(() => {
|
||||
const userInfo = Cookies.get("userInfo");
|
||||
if (userInfo) {
|
||||
try {
|
||||
const parsedUserInfo = JSON.parse(userInfo);
|
||||
const roles = parsedUserInfo?.roles || {};
|
||||
const hasRole = Object.values(roles).includes("representation");
|
||||
setHasRepresentationRole(hasRole);
|
||||
} catch (error) {
|
||||
console.error("Error parsing userInfo:", error);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
const open = Boolean(anchorEl);
|
||||
const id = open ? "simple-popover" : undefined;
|
||||
|
||||
@@ -74,18 +58,6 @@ function DetailProfile({ anchorEl, setAnchorEl }) {
|
||||
تراکنش های من
|
||||
</Button>
|
||||
</Link>
|
||||
{hasRepresentationRole && (
|
||||
<Link href="/panel/dashboard" className="w-full">
|
||||
<Button
|
||||
fullWidth
|
||||
variant="text"
|
||||
className="!text-[#7E7E7E] !text-[14px] !font-medium !flex !justify-start !p-[8px] !gap-[5px]"
|
||||
>
|
||||
<ProfilePA />
|
||||
داشبورد نماینده
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
<Button
|
||||
fullWidth
|
||||
color="error"
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import AddDoctorPage from "@/components/panel/addDoctor";
|
||||
|
||||
function AddDoctor() {
|
||||
return <AddDoctorPage />;
|
||||
}
|
||||
|
||||
export default AddDoctor;
|
||||
@@ -1,43 +0,0 @@
|
||||
import DashboardPage from "@/components/panel/dashboard";
|
||||
import { cookies } from "next/headers";
|
||||
import { fetchReq } from "@/lib/req";
|
||||
import { safeJsonParse } from "@/lib/sanitize";
|
||||
import { adaptRepresentationDashboard } from "@/lib/representationAdapters";
|
||||
import { getServerAccessToken } from "@/lib/serverToken";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
async function Dashboard() {
|
||||
const API_URL = process.env.NEXT_PUBLIC_API_URL;
|
||||
let dashboard = null;
|
||||
|
||||
try {
|
||||
const cookieStore = await cookies();
|
||||
const userInfo = cookieStore.get("userInfo");
|
||||
|
||||
if (userInfo) {
|
||||
const parsedUserInfo = safeJsonParse(userInfo.value);
|
||||
const representationUuid = parsedUserInfo?.representation_uuid;
|
||||
|
||||
if (representationUuid) {
|
||||
const accessToken = await getServerAccessToken();
|
||||
if (accessToken) {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = now.getMonth() + 1;
|
||||
|
||||
dashboard = await fetchReq(
|
||||
`${API_URL}/api/v1/representation/${representationUuid}/dashboard/monthly?year=${year}&month=${month}`,
|
||||
{ headers: { Authorization: `Bearer ${accessToken}` } }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching representation dashboard:", error);
|
||||
}
|
||||
|
||||
return <DashboardPage data={adaptRepresentationDashboard(dashboard)} />;
|
||||
}
|
||||
|
||||
export default Dashboard;
|
||||
@@ -1,51 +0,0 @@
|
||||
import Content from "@/components/panel/Content";
|
||||
import { defineAbilitiesFor } from "@/lib/ability";
|
||||
import { getUser } from "@/lib/auth";
|
||||
import { redirect } from "next/navigation";
|
||||
import { cookies } from "next/headers";
|
||||
import { fetchReq } from "@/lib/req";
|
||||
import { safeJsonParse } from "@/lib/sanitize";
|
||||
import { getServerAccessToken } from "@/lib/serverToken";
|
||||
|
||||
async function LayoutPanel({ children }) {
|
||||
const user = await getUser();
|
||||
const ability = defineAbilitiesFor(user);
|
||||
|
||||
if (!ability.can("access", "Panel")) {
|
||||
return redirect("/");
|
||||
}
|
||||
|
||||
let representationInfo = null;
|
||||
const API_URL = process.env.NEXT_PUBLIC_API_URL;
|
||||
|
||||
try {
|
||||
const cookieStore = await cookies();
|
||||
const userInfo = cookieStore.get("userInfo");
|
||||
|
||||
if (userInfo) {
|
||||
const parsedUserInfo = safeJsonParse(userInfo.value);
|
||||
if (!parsedUserInfo) return;
|
||||
const representationUuid = parsedUserInfo?.representation_uuid;
|
||||
|
||||
if (representationUuid) {
|
||||
const accessToken = await getServerAccessToken();
|
||||
if (accessToken) {
|
||||
representationInfo = await fetchReq(
|
||||
`${API_URL}/api/v1/representation/${representationUuid}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching representation info:", error);
|
||||
}
|
||||
|
||||
return <Content children={children} representationInfo={representationInfo} />;
|
||||
}
|
||||
|
||||
export default LayoutPanel;
|
||||
@@ -1,43 +0,0 @@
|
||||
import TurnsPage from "@/components/panel/turns";
|
||||
import { cookies } from "next/headers";
|
||||
import { fetchReq } from "@/lib/req";
|
||||
import { safeJsonParse } from "@/lib/sanitize";
|
||||
import { adaptRepresentationDashboard } from "@/lib/representationAdapters";
|
||||
import { getServerAccessToken } from "@/lib/serverToken";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
async function page() {
|
||||
const API_URL = process.env.NEXT_PUBLIC_API_URL;
|
||||
let dashboard = null;
|
||||
|
||||
try {
|
||||
const cookieStore = await cookies();
|
||||
const userInfo = cookieStore.get("userInfo");
|
||||
|
||||
if (userInfo) {
|
||||
const parsedUserInfo = safeJsonParse(userInfo.value);
|
||||
const representationUuid = parsedUserInfo?.representation_uuid;
|
||||
|
||||
if (representationUuid) {
|
||||
const accessToken = await getServerAccessToken();
|
||||
if (accessToken) {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = now.getMonth() + 1;
|
||||
|
||||
dashboard = await fetchReq(
|
||||
`${API_URL}/api/v1/representation/${representationUuid}/dashboard/monthly?year=${year}&month=${month}`,
|
||||
{ headers: { Authorization: `Bearer ${accessToken}` } }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching representation turns:", error);
|
||||
}
|
||||
|
||||
return <TurnsPage data={adaptRepresentationDashboard(dashboard)} />;
|
||||
}
|
||||
|
||||
export default page;
|
||||
@@ -1,41 +0,0 @@
|
||||
import UserAccountPage from "@/components/panel/userAccount";
|
||||
import { cookies } from "next/headers";
|
||||
import { fetchReq } from "@/lib/req";
|
||||
import { safeJsonParse } from "@/lib/sanitize";
|
||||
import { adaptBankAccount } from "@/lib/representationAdapters";
|
||||
import { getServerAccessToken } from "@/lib/serverToken";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
async function UserAccount() {
|
||||
const API_URL = process.env.NEXT_PUBLIC_API_URL;
|
||||
let representation = null;
|
||||
|
||||
try {
|
||||
const cookieStore = await cookies();
|
||||
const userInfo = cookieStore.get("userInfo");
|
||||
|
||||
if (userInfo) {
|
||||
const parsedUserInfo = safeJsonParse(userInfo.value);
|
||||
const representationUuid = parsedUserInfo?.representation_uuid;
|
||||
|
||||
if (representationUuid) {
|
||||
const accessToken = await getServerAccessToken();
|
||||
if (accessToken) {
|
||||
representation = await fetchReq(
|
||||
`${API_URL}/api/v1/representation/${representationUuid}`,
|
||||
{ headers: { Authorization: `Bearer ${accessToken}` } }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching representation account:", error);
|
||||
}
|
||||
|
||||
const bank = adaptBankAccount(representation?.data?.bank_account);
|
||||
|
||||
return <UserAccountPage data={{ bank }} />;
|
||||
}
|
||||
|
||||
export default UserAccount;
|
||||
+1
-1
@@ -37,7 +37,7 @@ export default function robots() {
|
||||
rules: {
|
||||
userAgent: '*',
|
||||
allow: '/',
|
||||
disallow: ['/dashboard', '/panel'],
|
||||
disallow: ['/dashboard'],
|
||||
},
|
||||
sitemap: `${baseUrl}/sitemap.xml`,
|
||||
};
|
||||
|
||||
@@ -8,10 +8,8 @@ import ProfileD from "@/components/icons/ProfileD";
|
||||
import NotificationD from "@/components/icons/NotificationD";
|
||||
import { Button } from "@mui/material";
|
||||
import ArrowLeftSideBar from "@/components/icons/ArrowLeftSideBar";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState } from "react";
|
||||
import ModalLogout from "../../../app/component/ModalLogout";
|
||||
import Cookies from "js-cookie";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
function List({
|
||||
value,
|
||||
@@ -20,44 +18,13 @@ function List({
|
||||
setIsTurnsDetails,
|
||||
setIsOpenSide,
|
||||
}) {
|
||||
const router = useRouter();
|
||||
const [hasRepresentationRole, setHasRepresentationRole] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const userInfo = Cookies.get("userInfo");
|
||||
if (userInfo) {
|
||||
try {
|
||||
const parsedUserInfo = JSON.parse(userInfo);
|
||||
const roles = parsedUserInfo?.roles || {};
|
||||
const hasRole = Object.values(roles).includes("representation");
|
||||
setHasRepresentationRole(hasRole);
|
||||
} catch (error) {
|
||||
console.error("Error parsing userInfo:", error);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
const baseListMenu = [
|
||||
const listMenu = [
|
||||
{ name: "حساب کاربری", icon: <ProfileD active={value === 0} />, action: "tab" },
|
||||
{ name: "نوبت های من", icon: <CalndarD active={value === 1} />, action: "tab" },
|
||||
{ name: "تراکنش های من", icon: <CardD active={value === 2} />, action: "tab" },
|
||||
];
|
||||
|
||||
// اگر نقش representation دارد، داشبورد نماینده را اضافه کن
|
||||
if (hasRepresentationRole) {
|
||||
baseListMenu.push({
|
||||
name: "داشبورد نماینده",
|
||||
icon: <ProfileD active={value === 3} />,
|
||||
action: "navigate",
|
||||
path: "/panel/dashboard"
|
||||
});
|
||||
}
|
||||
|
||||
const listMenu = [
|
||||
...baseListMenu,
|
||||
{ name: "نظرات من", icon: <MessageD active={value === hasRepresentationRole ? 4 : 3} />, action: "tab" },
|
||||
{ name: "پیام ها", icon: <NotificationD active={value === hasRepresentationRole ? 5 : 4} />, action: "tab" },
|
||||
{ name: "خروج", icon: <LogoutD active={value === hasRepresentationRole ? 6 : 5} />, action: "logout" },
|
||||
{ name: "نظرات من", icon: <MessageD active={value === 3} />, action: "tab" },
|
||||
{ name: "پیام ها", icon: <NotificationD active={value === 4} />, action: "tab" },
|
||||
{ name: "خروج", icon: <LogoutD active={value === 5} />, action: "logout" },
|
||||
];
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
@@ -70,8 +37,6 @@ function List({
|
||||
|
||||
if (item.action === "logout") {
|
||||
handleOpen();
|
||||
} else if (item.action === "navigate") {
|
||||
router.push(item.path);
|
||||
} else {
|
||||
setValue(idx);
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
import { useState } from "react";
|
||||
import { Button } from "@mui/material";
|
||||
import ArrowBottomHD from "@/components/icons/ArrowBottomHD";
|
||||
import Image from "next/image";
|
||||
import DetailProfile from "@/app/component/DetailProfile";
|
||||
|
||||
function MenuProfile({ data }) {
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
|
||||
const handleClick = (event) => setAnchorEl(event.currentTarget);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Image
|
||||
className="flex md:hidden w-[32px] h-[32px] rounded-full"
|
||||
src={data.src}
|
||||
alt="profile"
|
||||
height={32}
|
||||
width={32}
|
||||
/>
|
||||
<Button
|
||||
variant="text"
|
||||
onClick={handleClick}
|
||||
className="!hidden md:!flex !items-start !justify-center !gap-[8px] !p-1"
|
||||
>
|
||||
<Image
|
||||
className="w-[48px] h-[48px] rounded-full"
|
||||
src={data.src}
|
||||
alt="profile"
|
||||
height={48}
|
||||
width={48}
|
||||
/>
|
||||
<div className="flex flex-col items-start justify-between gap-[3px]">
|
||||
<p className="text-[#3B3B3B] dark:text-[#D7D8ED] text-[14px] font-semibold">
|
||||
دکتر {data.name}
|
||||
</p>
|
||||
<p className="text-[#7E7E7E] dark:text-[#A1A1A1] text-[12px] font-normal">
|
||||
{data.expertise}
|
||||
</p>
|
||||
</div>
|
||||
<div className="mr-[4px]">
|
||||
<ArrowBottomHD />
|
||||
</div>
|
||||
</Button>
|
||||
<DetailProfile anchorEl={anchorEl} setAnchorEl={setAnchorEl} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default MenuProfile;
|
||||
@@ -1,27 +0,0 @@
|
||||
import SearchHeaderP from "@/components/icons/SearchHeaderP";
|
||||
import { InputAdornment, TextField } from "@mui/material";
|
||||
|
||||
function Search() {
|
||||
return (
|
||||
<TextField
|
||||
fullWidth
|
||||
placeholder="جستجو"
|
||||
className="!hidden md:!flex"
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchHeaderP />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
sx={{
|
||||
"& .MuiOutlinedInput-input": {
|
||||
paddingTop: "9px !important",
|
||||
paddingBottom: "9px !important",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default Search;
|
||||
@@ -1,68 +0,0 @@
|
||||
import SearchHeaderP from "@/components/icons/SearchHeaderP";
|
||||
import { Button, Popover, TextField } from "@mui/material";
|
||||
import { useState } from "react";
|
||||
|
||||
function Search() {
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
|
||||
const handleClick = (event) => setAnchorEl(event.currentTarget);
|
||||
const handleClose = () => setAnchorEl(null);
|
||||
|
||||
const open = Boolean(anchorEl);
|
||||
const id = open ? "simple-popover" : undefined;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
className="
|
||||
!p-[8px] !border-[#EFEFEF] !rounded-[8px]
|
||||
!w-[32px] md:!w-[36px] lg:!w-[40px] dark:!border-[#343645]
|
||||
!h-[32px] md:!h-[36px] lg:!h-[40px] md:!hidden
|
||||
!min-w-[32px] md:!min-w-[36px] lg:!min-w-[40px]
|
||||
!min-h-[32px] md:!min-h-[36px] lg:!min-h-[40px]
|
||||
"
|
||||
variant="outlined"
|
||||
onClick={handleClick}
|
||||
>
|
||||
<SearchHeaderP />
|
||||
</Button>
|
||||
<Popover
|
||||
id={id}
|
||||
open={open}
|
||||
anchorEl={anchorEl}
|
||||
onClose={handleClose}
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "left",
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
size="small"
|
||||
placeholder="جستجو کنید.."
|
||||
sx={{
|
||||
"& .MuiFormLabel-root": {
|
||||
top: "-4px !important",
|
||||
},
|
||||
"& .MuiInputBase-input": { padding: "8px" },
|
||||
"& .MuiInputBase-root": { borderRadius: "6px !important" },
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
border: "1px solid #E9ECEF !important",
|
||||
},
|
||||
".Mui-focused": {
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
border: "1px solid #5559CE !important",
|
||||
transition: "0.5s all",
|
||||
},
|
||||
},
|
||||
"& input::-webkit-outer-spin-button, & input::-webkit-inner-spin-button":
|
||||
{
|
||||
display: "none",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Popover>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Search;
|
||||
@@ -1,36 +0,0 @@
|
||||
import MoonP from "@/components/icons/MoonP";
|
||||
import Sun from "@/components/icons/Sun";
|
||||
import { Button } from "@mui/material";
|
||||
import { useTheme } from "next-themes";
|
||||
import { useState } from "react";
|
||||
|
||||
function Theme() {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const { theme, setTheme } = useTheme();
|
||||
|
||||
useState(() => setMounted(true), []);
|
||||
|
||||
return (
|
||||
<Button
|
||||
className="
|
||||
!p-[8px] !border-[#EFEFEF] !rounded-[8px]
|
||||
!w-[32px] md:!w-[36px] lg:!w-[40px] dark:!border-[#343645]
|
||||
!h-[32px] md:!h-[36px] lg:!h-[40px]
|
||||
!min-w-[32px] md:!min-w-[36px] lg:!min-w-[40px]
|
||||
!min-h-[32px] md:!min-h-[36px] lg:!min-h-[40px]
|
||||
"
|
||||
// onClick={handleThemeSwitch}
|
||||
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
|
||||
variant="outlined"
|
||||
>
|
||||
<div className="block dark:hidden">
|
||||
<MoonP />
|
||||
</div>
|
||||
<div className="hidden dark:block">
|
||||
<Sun />
|
||||
</div>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
export default Theme;
|
||||
@@ -1,42 +0,0 @@
|
||||
import { Button } from "@mui/material";
|
||||
import NotificationP from "@/components/icons/NotificationP";
|
||||
import SettingP from "@/components/icons/SettingP";
|
||||
import Theme from "./Theme";
|
||||
import Search from "./Search";
|
||||
|
||||
function Icons() {
|
||||
return (
|
||||
<div className="flex items-center justify-start gap-[6px]">
|
||||
<Theme />
|
||||
<Search />
|
||||
<Button
|
||||
className="
|
||||
!p-[8px] !border-[#EFEFEF] !rounded-[8px]
|
||||
!w-[32px] md:!w-[36px] lg:!w-[40px] dark:!border-[#343645]
|
||||
!h-[32px] md:!h-[36px] lg:!h-[40px]
|
||||
!min-w-[32px] md:!min-w-[36px] lg:!min-w-[40px]
|
||||
!min-h-[32px] md:!min-h-[36px] lg:!min-h-[40px]
|
||||
"
|
||||
variant="outlined"
|
||||
>
|
||||
<SettingP />
|
||||
</Button>
|
||||
<Button
|
||||
className="
|
||||
!w-[32px] md:!w-[36px] lg:!w-[40px]
|
||||
!h-[32px] md:!h-[36px] lg:!h-[40px] dark:!border-[#343645]
|
||||
!min-w-[32px] md:!min-w-[36px] lg:!min-w-[40px]
|
||||
!min-h-[32px] md:!min-h-[36px] lg:!min-h-[40px]
|
||||
!p-[8px] !border-[#EFEFEF] !rounded-[8px] !relative before:!rounded-full
|
||||
before:!absolute before:!right-[-2px] before:!top-[-2px] before:!w-[6px] before:!h-[6px]
|
||||
before:!bg-[#D32F2F]
|
||||
"
|
||||
variant="outlined"
|
||||
>
|
||||
<NotificationP />
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Icons;
|
||||
@@ -1,25 +0,0 @@
|
||||
import Icons from "./icons";
|
||||
import Search from "./Search";
|
||||
import SideButton from "./sideButton";
|
||||
import MenuProfile from "./MenuProfile";
|
||||
|
||||
function Header({ disableProfile, data, setActive }) {
|
||||
return (
|
||||
<div
|
||||
className="
|
||||
h-[56px] sm:h-[67px] md:h-[79px] lg:h-[90px] top-0 right-0 sticky border-0 border-b border-[#EFEFEF] bg-[#FFF]
|
||||
dark:bg-[#222433] dark:border-transparent
|
||||
flex items-center justify-between pr-[16px] pl-[18px] z-20 gap-[14px] sm:gap-[28px] md:gap-[42px] lg:gap-[56px]
|
||||
"
|
||||
>
|
||||
<SideButton setActive={setActive} />
|
||||
<Search />
|
||||
<div className="flex items-center justify-end gap-[8px] md:gap-[40px] min-w-fit">
|
||||
<Icons />
|
||||
{!disableProfile && <MenuProfile data={data} />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Header;
|
||||
@@ -1,16 +0,0 @@
|
||||
import { Button } from "@mui/material";
|
||||
|
||||
function ButtonMenu({ setActive }) {
|
||||
return (
|
||||
<Button
|
||||
onClick={() => setActive(true)}
|
||||
className="!py-[6px] !px-[2px] !flex !p-0.5 !w-[24px] !h-[24px] !flex-col !justify-between !items-center"
|
||||
>
|
||||
<span className="min-h-[2px] transition-all duration-500 ease-in-out rounded-[40px] bg-[#6C757D] rotate-0 w-full"></span>
|
||||
<span className="w-full min-h-[2px] transition-all duration-500 ease-in-out rounded-[40px] bg-[#6C757D] rotate-180"></span>
|
||||
<span className="min-h-[2px] transition-all duration-500 ease-in-out rounded-[40px] bg-[#6C757D] rotate-0 w-full"></span>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
export default ButtonMenu;
|
||||
@@ -1,15 +0,0 @@
|
||||
import ButtonMenu from "./ButtonMenu";
|
||||
import LogoPanelHead from "@/components/icons/LogoPanelHead";
|
||||
|
||||
function SideButton({ setActive }) {
|
||||
return (
|
||||
<div className="flex md:hidden items-center justify-start gap-[4px]">
|
||||
<ButtonMenu setActive={setActive} />
|
||||
<div className="w-[100px] h-[24px]">
|
||||
<LogoPanelHead />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SideButton;
|
||||
@@ -1,20 +0,0 @@
|
||||
import Header from "./header";
|
||||
import Sidebar from "./sidebar";
|
||||
import UserDetail from "./userDetail";
|
||||
|
||||
function LayoutPanel({ children, data }) {
|
||||
return (
|
||||
<div className="flex min-h-screen">
|
||||
<Sidebar />
|
||||
<main className="w-full">
|
||||
<Header />
|
||||
<section className="my-[24px] opacity-element mx-[16px] bg-[#FAFAFA]">
|
||||
{children}
|
||||
</section>
|
||||
</main>
|
||||
<UserDetail data={data} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default LayoutPanel;
|
||||
@@ -1,17 +0,0 @@
|
||||
function BgGray({ isActive, setIsActive }) {
|
||||
return (
|
||||
<div
|
||||
onClick={() => setIsActive(false)}
|
||||
className={`
|
||||
md:hidden ${
|
||||
isActive
|
||||
? "bg-[#232323] opacity-40 flex"
|
||||
: "bg-transparent opacity-40 hidden"
|
||||
}
|
||||
absolute z-[25] cursor-pointer transition-all duration-500 left-0 top-0 w-screen h-screen
|
||||
`}
|
||||
></div>
|
||||
);
|
||||
}
|
||||
|
||||
export default BgGray;
|
||||
@@ -1,32 +0,0 @@
|
||||
import DoubleArrowLeftP from "@/components/icons/DoubleArrowLeftP";
|
||||
import LogoPanel from "@/components/icons/LogoPanel";
|
||||
import { Button } from "@mui/material";
|
||||
import Link from "next/link";
|
||||
import React from "react";
|
||||
|
||||
function HeadMd({ open, setOpen }) {
|
||||
return (
|
||||
<div
|
||||
className={`hidden md:flex w-full items-center transition-all duration-500 justify-between`}
|
||||
>
|
||||
<Link
|
||||
href="/panel/dashboard"
|
||||
className={`flex justify-center transition-all duration-500 logo-sidebar ${
|
||||
open ? "max-w-full" : "max-w-0"
|
||||
}`}
|
||||
>
|
||||
<LogoPanel />
|
||||
</Link>
|
||||
<Button
|
||||
onClick={() => setOpen(!open)}
|
||||
className={`!p-1 !grid !place-items-center !rounded-full !border !border-solid !border-[#EFEFEF]
|
||||
!transition-all !duration-500 !bg-[#FFF] !w-[28px] !h-[28px] !z-[320] dark:!bg-[#222433] dark:!border-[#343645]
|
||||
${open ? "!rotate-180" : "!rotate-0 !ml-[7px]"}`}
|
||||
>
|
||||
<DoubleArrowLeftP />
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default HeadMd;
|
||||
@@ -1,22 +0,0 @@
|
||||
import { Button } from "@mui/material";
|
||||
import ArrowRightP from "@/components/icons/ArrowRightP";
|
||||
import LogoPanelHead from "@/components/icons/LogoPanelHead";
|
||||
|
||||
function HeadSm({ setActive }) {
|
||||
return (
|
||||
<div className="flex md:hidden items-center justify-start gap-[8px]">
|
||||
<Button
|
||||
variant="text"
|
||||
className="!min-w-0 !p-1"
|
||||
onClick={() => setActive(false)}
|
||||
>
|
||||
<ArrowRightP />
|
||||
</Button>
|
||||
<div className="w-[100px] h-[23px]">
|
||||
<LogoPanelHead />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default HeadSm;
|
||||
@@ -1,73 +0,0 @@
|
||||
import Link from "next/link";
|
||||
import { Button } from "@mui/material";
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
// Icons
|
||||
import CalendarP from "@/components/icons/CalendarP";
|
||||
import CategoryP from "@/components/icons/CategoryP";
|
||||
import ProfileAddP from "@/components/icons/ProfileAddP";
|
||||
import ProfileCircleP from "@/components/icons/ProfileCircleP";
|
||||
|
||||
function Links({ open, setActive }) {
|
||||
const list = [
|
||||
{ name: "دشبورد", src: "/panel/dashboard", icon: <CategoryP /> },
|
||||
{
|
||||
name: "حساب کاربری",
|
||||
src: "/panel/user-account",
|
||||
icon: <ProfileCircleP />,
|
||||
},
|
||||
{
|
||||
name: "اضافه کردن پزشک",
|
||||
src: "/panel/add-doctor",
|
||||
icon: <ProfileAddP />,
|
||||
},
|
||||
{ name: "نوبت ها", src: "/panel/turns", icon: <CalendarP /> },
|
||||
];
|
||||
|
||||
const pathname = usePathname();
|
||||
|
||||
return (
|
||||
<ul
|
||||
className={`flex flex-col gap-[32px] mt-[36px] md:mt-[54px] transition-all duration-500`}
|
||||
>
|
||||
{list.map((item, idx) => (
|
||||
<li key={idx}>
|
||||
<Link href={item.src}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="text"
|
||||
onClick={() => setActive(false)}
|
||||
className={`
|
||||
!p-[8px] !flex !items-center !justify-start !gap-[8px] !text-[16px] !rounded-[8px] !transition-all !duration-500
|
||||
${
|
||||
item.src === pathname
|
||||
? "!bg-[#5559CE] dark:!bg-[#1F1D2B] dark-active-icon"
|
||||
: ""
|
||||
}
|
||||
`}
|
||||
>
|
||||
<div className="p-[3px] bg-[#E5E9FF] dark:bg-transparent rounded-[4px] w-fit">
|
||||
<div className="w-[20px] h-[20px]">{item.icon}</div>
|
||||
</div>
|
||||
<p
|
||||
className={`
|
||||
transition-all duration-500 text-sidebar
|
||||
${open ? "opacity-100" : "md:opacity-0"}
|
||||
${
|
||||
item.src === pathname
|
||||
? "!text-[#FAFAFA] dark:!text-[#5559CE] !font-bold"
|
||||
: "!text-[#525252] dark:!text-[#A1A1A1] !font-medium"
|
||||
}
|
||||
`}
|
||||
>
|
||||
{item.name}
|
||||
</p>
|
||||
</Button>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
export default Links;
|
||||
@@ -1,66 +0,0 @@
|
||||
import Links from "./Links";
|
||||
import HeadMd from "./HeadMd";
|
||||
import HeadSm from "./HeadSm";
|
||||
import { Button } from "@mui/material";
|
||||
import LogoutOrangeP from "@/components/icons/LogoutOrangeP";
|
||||
import ModalLogout from "@/app/component/ModalLogout";
|
||||
import { useState } from "react";
|
||||
|
||||
function Sidebar({ active, setActive, open, setOpen }) {
|
||||
const [modal, setModal] = useState(false);
|
||||
const handleOpen = () => setModal(true);
|
||||
const handleClose = () => setModal(false);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
transition-all duration-500 md:flex fixed md:relative z-30 w-[85%] hover-sidebar
|
||||
${active ? " right-0" : "right-[-85%]"}
|
||||
${open ? "min-w-[243px] md:w-[243px]" : "min-w-[92px] md:w-[92px]"}
|
||||
`}
|
||||
>
|
||||
<aside
|
||||
className={`
|
||||
relative h-screen overflow-hidden
|
||||
transition-all duration-500 w-[85%]
|
||||
${active ? " right-0" : "right-[-85%]"}
|
||||
${open ? "w-[243px]" : "w-[92px] hover:w-[243px]"}
|
||||
`}
|
||||
>
|
||||
<div
|
||||
className={`
|
||||
z-30 md:top-0 md:right-0 w-[85%]
|
||||
${active ? " right-0" : "right-[-85%]"}
|
||||
overflow-hidden p-[24px] h-full flex flex-col justify-between items-start fixed
|
||||
border-0 border-l border-l-[#EFEFEF] bg-[#FFF] dark:bg-[#222433]
|
||||
transition-all duration-500 dark:border-transparent
|
||||
${open ? "md:w-[243px]" : "md:w-[92px] hover:md:w-[243px]"}
|
||||
`}
|
||||
>
|
||||
<div className="w-full">
|
||||
<HeadMd open={open} setOpen={setOpen} />
|
||||
<HeadSm setActive={setActive} />
|
||||
<Links open={open} setActive={setActive} />
|
||||
</div>
|
||||
<div
|
||||
className={`w-full flex logout-btn justify-center overflow-hidden transition-all duration-500 ${
|
||||
open ? "!max-w-full" : "!max-w-[36px]"
|
||||
}`}
|
||||
>
|
||||
<Button
|
||||
variant="text"
|
||||
onClick={handleOpen}
|
||||
className="!flex !w-fit !items-center !justify-start !gap-[10px] !py-[8px] !px-[16px] !text-[#F17732] !text-[16px] !font-medium"
|
||||
>
|
||||
<LogoutOrangeP />
|
||||
خروج از حساب
|
||||
</Button>
|
||||
<ModalLogout open={modal} handleClose={handleClose} />
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Sidebar;
|
||||
@@ -1,40 +0,0 @@
|
||||
import TextLoading from "@/app/component/loading/Text";
|
||||
import WarnP from "@/components/icons/WarnP";
|
||||
|
||||
function Activities({ data, loading }) {
|
||||
return (
|
||||
<div className="w-full mt-[16px] sm:mt-[24px] md:mt-[32px] lg:mt-[40px]">
|
||||
<p className="text-[#525252] text-[14px] md:text-[16px] font-bold dark:text-[#D7D8ED]">
|
||||
فعالیت های امروز
|
||||
</p>
|
||||
<ul className="flex flex-col justify-start w-full mt-[24px]">
|
||||
{data.todays_activities.map((item, idx) => (
|
||||
<li key={idx} className="flex flex-col">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center justify-start gap-[12px]">
|
||||
<div className="bg-[rgba(255,192,81,0.20)] dark:bg-[rgba(255,192,81,0.10)] p-[8px] rounded-full">
|
||||
<WarnP />
|
||||
</div>
|
||||
<TextLoading width={110} height={18} loading={loading}>
|
||||
<p className="text-[#616161] dark:text-[#A1A1A1] text-[16px] font-medium">
|
||||
{item.text}
|
||||
</p>
|
||||
</TextLoading>
|
||||
</div>
|
||||
<TextLoading width={55} height={18} loading={loading}>
|
||||
<p className="text-[#7E7E7E] dark:text-[#A1A1A1] text-[12px] font-normal">
|
||||
{item.time}
|
||||
</p>
|
||||
</TextLoading>
|
||||
</div>
|
||||
{data.todays_activities.length > idx + 1 && (
|
||||
<span className="block h-px w-full bg-transparent md:bg-[#EFEFEF] dark:bg-[#343645] px-[13px] my-[16px] md:my-[20px] lg:my-[24px]"></span>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Activities;
|
||||
@@ -1,41 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import JalaliDatePicker from "@/components/common/JalaliDatePicker";
|
||||
|
||||
function Date() {
|
||||
return (
|
||||
<div className="flex justify-center sm-datepicker active-today jalali-dashboard">
|
||||
<JalaliDatePicker
|
||||
nextIcon={<></>}
|
||||
prevIcon={<></>}
|
||||
dayLabelRender={() => (
|
||||
<div className="day-label-bar-inner-rtl">
|
||||
<div className="day-label-item !text-[10px] font-semibold">
|
||||
شنبه
|
||||
</div>
|
||||
<div className="day-label-item !text-[10px] font-semibold">
|
||||
۱ شنبه
|
||||
</div>
|
||||
<div className="day-label-item !text-[10px] font-semibold">
|
||||
۲ شنبه
|
||||
</div>
|
||||
<div className="day-label-item !text-[10px] font-semibold">
|
||||
۳ شنبه
|
||||
</div>
|
||||
<div className="day-label-item !text-[10px] font-semibold">
|
||||
۴ شنبه
|
||||
</div>
|
||||
<div className="day-label-item !text-[10px] font-semibold">
|
||||
۵ شنبه
|
||||
</div>
|
||||
<div className="day-label-item !text-[10px] font-semibold">
|
||||
جمعه
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Date;
|
||||
@@ -1,66 +0,0 @@
|
||||
import CircularLoading from "@/app/component/loading/Circular";
|
||||
import TextLoading from "@/app/component/loading/Text";
|
||||
import ArrowLeftBlueP from "@/components/icons/ArrowLeftBlueP";
|
||||
import LocationP from "@/components/icons/LocationP";
|
||||
import { Button } from "@mui/material";
|
||||
import Image from "next/image";
|
||||
import React from "react";
|
||||
|
||||
function Head({ data, loading, representationInfo }) {
|
||||
const cityName = representationInfo?.city?.label || "اهواز";
|
||||
|
||||
return (
|
||||
<div className="flex w-full flex-col items-center justify-start">
|
||||
<CircularLoading width={80} height={80} loading={loading}>
|
||||
<Image src={data.src} height={80} width={80} alt="profile" />
|
||||
</CircularLoading>
|
||||
<div className={loading ? "mt-[8px] mb-[4px]" : ""}>
|
||||
<TextLoading width={60} height={18} loading={loading}>
|
||||
<p className="text-[#3B3B3B] text-[14px] font-semibold mt-[8px] mb-[4px] dark:text-[#fafafa]">
|
||||
{data.name}
|
||||
</p>
|
||||
</TextLoading>
|
||||
</div>
|
||||
<div className="flex items-center justify-center gap-[8px]">
|
||||
<LocationP />
|
||||
<TextLoading width={55} height={16} loading={loading}>
|
||||
<p className="text-[#7E7E7E] text-[14px] font-normal dark:text-[#A1A1A1]">
|
||||
نماینده شهر {cityName}
|
||||
</p>
|
||||
</TextLoading>
|
||||
</div>
|
||||
<div className="flex items-center justify-center my-[16px]">
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<p className="text-[#9B9B9B] text-[14px] font-normal dark:text-[#A1A1A1]">
|
||||
کل بیماران
|
||||
</p>
|
||||
<TextLoading width={55} height={16} loading={loading}>
|
||||
<p className="text-[#3B3B3B] text-[14px] font-medium dark:text-[#A1A1A1]">
|
||||
{data.all_patients}
|
||||
</p>
|
||||
</TextLoading>
|
||||
</div>
|
||||
<span className="block h-[44px] w-px bg-[#EFEFEF] mx-[44px] dark:bg-[#343645]"></span>
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<p className="text-[#9B9B9B] text-[14px] font-normal dark:text-[#A1A1A1]">
|
||||
کل نوبت ها
|
||||
</p>
|
||||
<TextLoading width={55} height={16} loading={loading}>
|
||||
<p className="text-[#3B3B3B] text-[14px] font-medium dark:text-[#A1A1A1]">
|
||||
{data.total_turns}
|
||||
</p>
|
||||
</TextLoading>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
className="!flex !p-1 !items-center !justify-center !text-[#5559CE] !text-[14px] !font-medium"
|
||||
variant="text"
|
||||
>
|
||||
مشاهده اطلاعات نماینده
|
||||
<ArrowLeftBlueP />
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Head;
|
||||
@@ -1,21 +0,0 @@
|
||||
import Head from "./Head";
|
||||
import Date from "./Date";
|
||||
import Activities from "./Activities";
|
||||
|
||||
function UserDetail({ data, loading, representationInfo }) {
|
||||
return (
|
||||
<div className="hidden xl:flex min-w-[332px] h-full opacity-page">
|
||||
<div
|
||||
className="min-w-[332px] p-[24px] border-0 border-r border-r-[#EFEFEF] h-full items-start fixed top-0 left-0
|
||||
g-[#FFF] py-[40px] px-[16px] bg-[#FFF] dark:bg-[#222433] dark:border-transparent"
|
||||
>
|
||||
<Head data={data} loading={loading} representationInfo={representationInfo} />
|
||||
<span className="block w-full h-px bg-[#EFEFEF] px-[22px] mt-[13px] mb-[16px] dark:bg-[#343645]"></span>
|
||||
<Date />
|
||||
<Activities data={data} loading={loading} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default UserDetail;
|
||||
@@ -1,70 +0,0 @@
|
||||
import CircularLoading from "@/app/component/loading/Circular";
|
||||
import TextLoading from "@/app/component/loading/Text";
|
||||
import Image from "next/image";
|
||||
|
||||
function ColTable({ data, loading }) {
|
||||
return (
|
||||
<ul className="grid grid-cols-1 sm:grid-cols-2 md:hidden flex-col gap-[16px]">
|
||||
{data.map((item, idx) => (
|
||||
<li
|
||||
key={idx}
|
||||
className="bg-[#FFF] p-[12px] rounded-[8px] shadow-[0px_1px_24.8px_0px_rgba(204,204,204,0.18)] dark:shadow-transparent dark:bg-[#222433]"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center justify-start gap-[8px] !text-nowrap">
|
||||
<CircularLoading width={32} height={32} loading={loading}>
|
||||
<Image src={item.image} alt="doctor" height={32} width={32} />
|
||||
</CircularLoading>
|
||||
<TextLoading width={40} height={18} loading={loading}>
|
||||
<p className="text-[#616161] dark:text-[#D7D8ED]">
|
||||
{item.name}
|
||||
</p>
|
||||
</TextLoading>
|
||||
</div>
|
||||
<TextLoading width={105} height={18} loading={loading}>
|
||||
<p className="px-[8px] py-[4px] text-[#F17732] dark:bg-[#4E2E39] dark:text-[#FF5450] text-[14px] font-medium bg-[rgba(255,216,197,0.50)] rounded-[4px]">
|
||||
تعداد نوبت: {item.number_of_turns}
|
||||
</p>
|
||||
</TextLoading>
|
||||
</div>
|
||||
<div className="flex flex-col mt-[16px]">
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-[#7E7E7E] dark:text-[#A1A1A1] text-[14px] font-normal">
|
||||
تخصص:
|
||||
</p>
|
||||
<TextLoading width={90} height={18} loading={loading}>
|
||||
<p className="text-[#616161] dark:text-[#A1A1A1] text-[14px] font-medium">
|
||||
{item.expertise}
|
||||
</p>
|
||||
</TextLoading>
|
||||
</div>
|
||||
<span className="block h-px w-full bg-[#EFEFEF] dark:bg-[#343645] my-[12px]"></span>
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-[#7E7E7E] dark:text-[#A1A1A1] text-[14px] font-normal">
|
||||
تاریخ نوبت:
|
||||
</p>
|
||||
<TextLoading width={85} height={18} loading={loading}>
|
||||
<p className="text-[#616161] dark:text-[#A1A1A1] text-[14px] font-medium">
|
||||
{item.date}
|
||||
</p>
|
||||
</TextLoading>
|
||||
</div>
|
||||
<span className="block h-px w-full bg-[#EFEFEF] dark:bg-[#343645] my-[12px]"></span>
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-[#7E7E7E] dark:text-[#A1A1A1] text-[14px] font-normal">
|
||||
ساعت نوبت:
|
||||
</p>
|
||||
<TextLoading width={60} height={18} loading={loading}>
|
||||
<p className="text-[#616161] dark:text-[#A1A1A1] text-[14px] font-medium">
|
||||
{item.hour}
|
||||
</p>
|
||||
</TextLoading>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
export default ColTable;
|
||||
@@ -1,66 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import Header from "@/components/layoutPanel/header";
|
||||
import Sidebar from "@/components/layoutPanel/sidebar";
|
||||
import UserDetail from "@/components/layoutPanel/userDetail";
|
||||
import { usePathname } from "next/navigation";
|
||||
import BgGray from "@/components/layoutPanel/sidebar/BgGray";
|
||||
import { adaptRepresentationInfo } from "@/lib/representationAdapters";
|
||||
|
||||
function Content({ children, representationInfo }) {
|
||||
const pathname = usePathname();
|
||||
const [active, setActive] = useState(false);
|
||||
const [open, setOpen] = useState(true);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const info = adaptRepresentationInfo(representationInfo);
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
setLoading(false);
|
||||
}, 2000);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen dark:bg-[#1F1D2B]">
|
||||
<Sidebar
|
||||
open={open}
|
||||
active={active}
|
||||
setOpen={setOpen}
|
||||
setActive={setActive}
|
||||
/>
|
||||
<BgGray isActive={active} setIsActive={setActive} />
|
||||
<main
|
||||
className={`
|
||||
w-full transition-all duration-500 dark:bg-[#1F1D2B]
|
||||
${pathname.includes("dashboard")
|
||||
? open
|
||||
? "md:min-w-[calc(100%_-_243px)] md:w-[calc(100%_-_243px)] xl:min-w-[calc(100%_-_243px_-_332px)] xl:w-[calc(100%_-_243px_-_332px)]"
|
||||
: "md:min-w-[calc(100%_-_96px)] md:w-[calc(100%_-_96px)] xl:min-w-[calc(100%_-_96px_-_332px)] xl:w-[calc(100%_-_96px_-_332px)]"
|
||||
: open
|
||||
? "md:w-[calc(100%-243px)]"
|
||||
: "md:w-[calc(100%-96px)]"
|
||||
}
|
||||
`}
|
||||
>
|
||||
<Header
|
||||
data={info}
|
||||
setActive={setActive}
|
||||
disableProfile={pathname.includes("dashboard")}
|
||||
/>
|
||||
<section className="my-[24px] opacity-element mx-[16px] bg-[#FAFAFA] dark:bg-[#1F1D2B]">
|
||||
{children}
|
||||
</section>
|
||||
</main>
|
||||
{pathname.includes("dashboard") && (
|
||||
<UserDetail
|
||||
data={info}
|
||||
loading={loading}
|
||||
representationInfo={representationInfo}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Content;
|
||||
@@ -1,15 +0,0 @@
|
||||
export const defaultState = {
|
||||
name: { value: "", placeholder: "", isEdit: true },
|
||||
medical_system_number: {
|
||||
value: "",
|
||||
placeholder: 1741025645,
|
||||
isEdit: true,
|
||||
},
|
||||
expertise: { value: "", placeholder: "دندان پزشکی", isEdit: true },
|
||||
description: { value: "", isEdit: true },
|
||||
skills: { value: [], isEdit: true },
|
||||
time_work: { value: "", isEdit: true },
|
||||
phone: { value: "", placeholder: "", isEdit: true },
|
||||
degree: { value: "", isEdit: true },
|
||||
gender: { value: "woman", isEdit: true },
|
||||
};
|
||||
@@ -1,97 +0,0 @@
|
||||
import Selector from "./fields/Selector";
|
||||
import ContentText from "@/app/component/ContentText";
|
||||
import EditField from "@/app/component/fields/EditField";
|
||||
import GroupedSelect from "@/app/component/selectors/GroupedSelect";
|
||||
import MultipleSelect from "@/app/component/selectors/MultipleSelect";
|
||||
|
||||
// Data
|
||||
import specialties from "@/data/specialties.json";
|
||||
import education from "@/data/education.json";
|
||||
|
||||
const validate_medical_number = {
|
||||
min: 1,
|
||||
max: 9999999999,
|
||||
};
|
||||
|
||||
function Fields({ services, data, updateNum, changeData }) {
|
||||
return (
|
||||
<>
|
||||
<ContentText text="نام و نام خانوادگی">
|
||||
<EditField
|
||||
isTransparent={true}
|
||||
iconGray={true}
|
||||
changeData={changeData}
|
||||
data={data?.name}
|
||||
placeholder={data?.name.placeholder}
|
||||
name="name"
|
||||
/>
|
||||
</ContentText>
|
||||
<ContentText text="شماره نظام پزشکی">
|
||||
<EditField
|
||||
isTransparent={true}
|
||||
iconGray={true}
|
||||
changeData={updateNum}
|
||||
data={data?.medical_system_number}
|
||||
noDisable={true}
|
||||
type="number"
|
||||
placeholder={data?.medical_system_number.placeholder}
|
||||
name="medical_system_number"
|
||||
props={{
|
||||
inputProps: validate_medical_number,
|
||||
}}
|
||||
/>
|
||||
</ContentText>
|
||||
<ContentText text="تخصص">
|
||||
<GroupedSelect
|
||||
updateData={changeData}
|
||||
data={data?.expertise.value}
|
||||
name="expertise"
|
||||
list={specialties}
|
||||
nameKey="name"
|
||||
/>
|
||||
</ContentText>
|
||||
<ContentText text="مدرک">
|
||||
<Selector
|
||||
updateData={changeData}
|
||||
label="انتخاب کنید..."
|
||||
name="degree"
|
||||
data={data?.degree.value}
|
||||
list={education}
|
||||
nameKey="label"
|
||||
/>
|
||||
</ContentText>
|
||||
<ContentText text="مهارت ها">
|
||||
<MultipleSelect
|
||||
name="skills"
|
||||
list={services}
|
||||
updateData={changeData}
|
||||
value={data?.skills.value}
|
||||
/>
|
||||
</ContentText>
|
||||
<ContentText text="شماره موبایل">
|
||||
<EditField
|
||||
isTransparent={true}
|
||||
iconGray={true}
|
||||
changeData={changeData}
|
||||
data={data?.phone}
|
||||
type="number"
|
||||
placeholder={data?.phone.placeholder}
|
||||
name="phone"
|
||||
/>
|
||||
</ContentText>
|
||||
<ContentText text="توضیحات">
|
||||
<EditField
|
||||
multiline={5}
|
||||
placeholder="درباره سوابق خود توضیحاتی بنویسید..."
|
||||
isTransparent={true}
|
||||
iconGray={true}
|
||||
changeData={changeData}
|
||||
data={data?.description}
|
||||
name="description"
|
||||
/>
|
||||
</ContentText>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Fields;
|
||||
@@ -1,54 +0,0 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import { convertToJalali } from "@/helper";
|
||||
import EditField from "@/app/component/fields/EditField";
|
||||
import ButtonDate from "@/app/component/ButtonDate";
|
||||
import CalendarPD from "@/components/icons/CalendarPD";
|
||||
import ContentText from "@/app/component/ContentText";
|
||||
|
||||
function FieldDate({ changeListData, data }) {
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const open = Boolean(anchorEl);
|
||||
const id = open ? "simple-popover" : undefined;
|
||||
|
||||
const updateDate = (newDate) => {
|
||||
const jalaliDate = newDate
|
||||
? convertToJalali(newDate)
|
||||
: "تاریخ مد نظر پیدا نشد...";
|
||||
changeListData(jalaliDate, "value", "time_work");
|
||||
};
|
||||
|
||||
const handleClick = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
return (
|
||||
<ContentText text="زمان شروع به کار">
|
||||
<ButtonDate
|
||||
setAnchorEl={setAnchorEl}
|
||||
updateDate={updateDate}
|
||||
anchorEl={anchorEl}
|
||||
open={open}
|
||||
id={id}
|
||||
>
|
||||
<div className="relative w-full">
|
||||
<EditField
|
||||
placeholder="انتخاب کنید..."
|
||||
changeData={changeListData}
|
||||
data={data}
|
||||
icon={<CalendarPD />}
|
||||
isTransparent={true}
|
||||
iconGray={true}
|
||||
name="time_work"
|
||||
/>
|
||||
<span
|
||||
className="absolute left-0 top-0 w-full h-full bg-transparent z-10 cursor-pointer"
|
||||
onClick={handleClick}
|
||||
></span>
|
||||
</div>
|
||||
</ButtonDate>
|
||||
</ContentText>
|
||||
);
|
||||
}
|
||||
|
||||
export default FieldDate;
|
||||
@@ -1,34 +0,0 @@
|
||||
import { FormControlLabel, Radio, RadioGroup } from "@mui/material";
|
||||
|
||||
function RadioGender({ changeData, name, data }) {
|
||||
return (
|
||||
<RadioGroup
|
||||
dir="ltr"
|
||||
value={data}
|
||||
className="!flex radio-mui !flex-row !gap-[36px] !items-center !justify-start"
|
||||
onChange={(e) => changeData(e.target.value, "value", name)}
|
||||
sx={{
|
||||
"& .muirtl-j204z7-MuiFormControlLabel-root": {
|
||||
marginLeft: "0 !important",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
label="مرد"
|
||||
value="man"
|
||||
control={<Radio />}
|
||||
dir="rtl"
|
||||
className="!text-[#A1A1A1]"
|
||||
/>
|
||||
<FormControlLabel
|
||||
label="زن"
|
||||
value="woman"
|
||||
control={<Radio />}
|
||||
dir="rtl"
|
||||
className="!text-[#A1A1A1]"
|
||||
/>
|
||||
</RadioGroup>
|
||||
);
|
||||
}
|
||||
|
||||
export default RadioGender;
|
||||
@@ -1,85 +0,0 @@
|
||||
import BottomSelect from "@/components/icons/BottomSelect";
|
||||
import { Autocomplete, Button, TextField } from "@mui/material";
|
||||
import { styleTextSelectRight } from "@/mui";
|
||||
|
||||
function Selector({ data, updateData, nameKey, label, name, list }) {
|
||||
const selectedOption = list.find((item) => item.id === data) || null;
|
||||
|
||||
return (
|
||||
<Autocomplete
|
||||
value={selectedOption}
|
||||
disablePortal
|
||||
options={list}
|
||||
getOptionLabel={(option) => option[nameKey] || ""}
|
||||
isOptionEqualToValue={(option, value) => option.id === value.id}
|
||||
className="!w-full !rounded-lg auto-complete-selector"
|
||||
onChange={(e, newValue) => {
|
||||
if (newValue) {
|
||||
updateData && updateData(newValue.id, "value", name);
|
||||
}
|
||||
}}
|
||||
sx={{
|
||||
...styleTextSelectRight,
|
||||
"& input::-webkit-outer-spin-button, & input::-webkit-inner-spin-button":
|
||||
{
|
||||
display: "none",
|
||||
},
|
||||
"& input[type=number]": {
|
||||
MozAppearance: "textfield",
|
||||
},
|
||||
"& .MuiInputBase-input": { padding: "12.5px 14px !important" },
|
||||
"& .MuiInputBase-root": {
|
||||
borderRadius: 2,
|
||||
padding: "0 !important",
|
||||
height: {
|
||||
xs: "43px !important",
|
||||
sm: "43px !important",
|
||||
md: "46px !important",
|
||||
lg: "48px !important",
|
||||
},
|
||||
},
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
border: "1px solid #D7D7D7",
|
||||
},
|
||||
"& .MuiInput-underline:hover:not(.Mui-disabled):before, .MuiOutlinedInput-notchedOutline":
|
||||
{
|
||||
borderColor: "#D7D7D7 !important",
|
||||
},
|
||||
"& .muirtl-1kiro5a-MuiInputBase-root-MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline":
|
||||
{
|
||||
border: "1px solid #5559CE !important",
|
||||
},
|
||||
}}
|
||||
renderOption={(props, option) => (
|
||||
<Button
|
||||
fullWidth
|
||||
{...props}
|
||||
key={option.id || props.id}
|
||||
className="!flex !justify-start !p-[8px] !text-start !text-[#A1A1A1] hover:dark:!bg-[#35343D] !bg-[#FFF] dark:!bg-[#1F1D2B]"
|
||||
>
|
||||
{option.name || option.label}
|
||||
</Button>
|
||||
)}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
fullWidth
|
||||
{...params}
|
||||
InputProps={{
|
||||
...params.InputProps,
|
||||
endAdornment: (
|
||||
<div className="absolute left-4">
|
||||
<BottomSelect />
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
placeholder={label}
|
||||
sx={{
|
||||
borderRadius: "8px",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default Selector;
|
||||
@@ -1,73 +0,0 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import FieldDate from "./fields/FieldDate";
|
||||
import RadioGender from "./fields/RadioGender";
|
||||
import SendReq from "./sendReq";
|
||||
import ContentText from "@/app/component/ContentText";
|
||||
import { request } from "@/services/response";
|
||||
import Fields from "./Fields";
|
||||
|
||||
const validate_medical_number = {
|
||||
min: 1,
|
||||
max: 9999999999,
|
||||
};
|
||||
|
||||
function Form({ image, data, setData, resetData }) {
|
||||
const [services, setServices] = useState([]);
|
||||
|
||||
const changeData = (value, type, name) => {
|
||||
type !== "isEdit" &&
|
||||
setData((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
[name]: {
|
||||
...prev[name],
|
||||
[type]: value,
|
||||
},
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const updateNum = (value, type, name) => {
|
||||
const parseValue = +value;
|
||||
const { max } = validate_medical_number;
|
||||
const validateValue = parseValue > max ? data[name].value : value;
|
||||
changeData(validateValue, type, name);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
request
|
||||
.getDoctorServices()
|
||||
.then((res) => {
|
||||
setServices(res.data);
|
||||
})
|
||||
.catch(() => {
|
||||
//
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mt-[24px] sm-modal scroll-mui md:mt-[26px] lg:mt-[28px] grid grid-cols-1 md:grid-cols-2 gap-x-[48px] gap-y-[24px]">
|
||||
<Fields
|
||||
data={data}
|
||||
services={services}
|
||||
updateNum={updateNum}
|
||||
changeData={changeData}
|
||||
/>
|
||||
<div className="flex flex-col gap-y-[24px]">
|
||||
<FieldDate changeListData={changeData} data={data?.time_work} />
|
||||
<ContentText text="جنسیت">
|
||||
<RadioGender
|
||||
changeData={changeData}
|
||||
data={data?.gender.value}
|
||||
name="gender"
|
||||
/>
|
||||
</ContentText>
|
||||
</div>
|
||||
</div>
|
||||
<SendReq img={image} data={data} resetData={resetData} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Form;
|
||||
@@ -1,13 +0,0 @@
|
||||
export const degree = [
|
||||
{ label: "مدرک 1", id: 10 },
|
||||
{ label: "مدرک 2", id: 20 },
|
||||
{ label: "مدرک 3", id: 30 },
|
||||
{ label: "مدرک 4", id: 40 },
|
||||
];
|
||||
|
||||
export const expertise = [
|
||||
{ label: "فوق تخصص", id: 10 },
|
||||
{ label: "دکترای تخصصی", id: 20 },
|
||||
{ label: "متخصص", id: 30 },
|
||||
{ label: "دکتری", id: 40 },
|
||||
];
|
||||
@@ -1,21 +0,0 @@
|
||||
import moment from "jalali-moment";
|
||||
|
||||
export const dateToTimestamp = (date) => {
|
||||
const gregorianMoment = moment(date, "jYYYY/jM/jD").locale("fa");
|
||||
const unixTimestamp = gregorianMoment.valueOf();
|
||||
return unixTimestamp / 1000;
|
||||
};
|
||||
|
||||
export const transformData = (data) => {
|
||||
return {
|
||||
name: data.name.value,
|
||||
activity_time: dateToTimestamp(data.time_work.value),
|
||||
doctor_mobile_number: data.phone.value,
|
||||
degree: data.degree.value,
|
||||
specialty: [data.expertise.value],
|
||||
info: data.description.value,
|
||||
doctor_id: data.medical_system_number.value,
|
||||
doctor_services: data.skills.value,
|
||||
gender: data.gender.value,
|
||||
};
|
||||
};
|
||||
@@ -1,68 +0,0 @@
|
||||
import ArrowLeftPA from "@/components/icons/ArrowLeftPA";
|
||||
import { alert, checkAllValues } from "@/helper";
|
||||
import { request } from "@/services/response";
|
||||
import { Button } from "@mui/material";
|
||||
import { useState } from "react";
|
||||
import { transformData } from "./function";
|
||||
|
||||
function SendReq({ img, data, resetData }) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const saveData = (img) => {
|
||||
let transformed = transformData(data);
|
||||
|
||||
if (img) {
|
||||
transformed.image = [img];
|
||||
}
|
||||
|
||||
request
|
||||
.postDoctor(transformed)
|
||||
.then((res) => {
|
||||
if (res.id) {
|
||||
alert("success", "پزشک جدید با موفقیت اضافه شد!");
|
||||
resetData();
|
||||
setLoading(false);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
setLoading(false);
|
||||
alert("error", "خطا در ثبت پزشک! لطفاً دوباره تلاش کنید.");
|
||||
});
|
||||
};
|
||||
|
||||
const saveImg = () => {
|
||||
resetData();
|
||||
setLoading(true);
|
||||
if (img) {
|
||||
request
|
||||
.postImageUpload(img.file)
|
||||
.then((res) => {
|
||||
const imgId = res.fid[0].value;
|
||||
saveData(imgId);
|
||||
})
|
||||
.catch(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
} else {
|
||||
saveData();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mt-[40px] w-full flex justify-end">
|
||||
<Button
|
||||
className="!w-full md:!w-fit !shadow-none !rounded-[4px] !gap-[4px] !text-[#EFEFEF] !text-[14px] md:!text-[16px] !font-medium"
|
||||
disabled={loading || !checkAllValues(data)}
|
||||
variant="contained"
|
||||
onClick={saveImg}
|
||||
>
|
||||
<p className={loading ? "opacity-0" : ""}>ثبت اطلاعات</p>
|
||||
<div className={!checkAllValues(data) ? "opacity-40" : "opacity-100"}>
|
||||
<ArrowLeftPA />
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SendReq;
|
||||
@@ -1,31 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import Form from "./form";
|
||||
import { useState } from "react";
|
||||
import { defaultState } from "./defaultState";
|
||||
import UploadFile from "@/app/component/uploadFile";
|
||||
|
||||
function AddDoctorPage() {
|
||||
const [data, setData] = useState(defaultState);
|
||||
const [image, setImage] = useState("");
|
||||
|
||||
const resetData = () => {
|
||||
setData(defaultState);
|
||||
setImage();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="opacity-page bg-transparent dark:shadow-[0px_4px_25px_10px_#1F1D2B] md:dark:bg-[#222433] md:bg-[#FFF] opacity-page rounded-[8px] shadow-none md:shadow-[0px_1px_24.8px_0px_rgba(204,204,204,0.18)] pt-0 md:pt-[12px] lg:pt-[24px] px-0 md:px-[24px] p-[24px]">
|
||||
<UploadFile image={image} setImage={setImage} />
|
||||
<Form
|
||||
data={data}
|
||||
image={image}
|
||||
parent={parent}
|
||||
setData={setData}
|
||||
resetData={resetData}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AddDoctorPage;
|
||||
@@ -1,63 +0,0 @@
|
||||
import CalendarTickGreenP from "../../icons/CalendarTickGreenP";
|
||||
import TextLoading from "@/app/component/loading/Text";
|
||||
import CardOrangeP from "../../icons/CardOrangeP";
|
||||
import PeopleBlueP from "../../icons/PeopleBlueP";
|
||||
|
||||
function Cards({ data, loading }) {
|
||||
const list = [
|
||||
{
|
||||
text: "تعداد کل بیماران",
|
||||
bg_color: "bg-[#E5E9FF] dark:bg-[#5559CE]",
|
||||
value: data.number_of_patients,
|
||||
label: "نفر",
|
||||
icon: <PeopleBlueP />,
|
||||
},
|
||||
{
|
||||
text: "نوبت های امروز",
|
||||
bg_color: "bg-[rgba(20,204,38,0.14)] dark:bg-[#009D79]",
|
||||
value: data.today_turns,
|
||||
label: "نوبت",
|
||||
icon: <CalendarTickGreenP />,
|
||||
},
|
||||
{
|
||||
text: "پرداختی ها",
|
||||
bg_color: "bg-[#FFD8C5] dark:bg-[#F17732]",
|
||||
value: data.payments,
|
||||
label: "تومان",
|
||||
icon: <CardOrangeP />,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<ul className="flex lg:grid lg:grid-cols-3 flex-wrap flex-col sm:flex-row items-center justify-center gap-[32px] mx-0 sm:mx-[16px]">
|
||||
{list.map((item, idx) => (
|
||||
<li
|
||||
className="flex min-w-[194px] w-full sm:w-auto flex-col py-[16px] md:py-[18px] px-[12px] gap-[8px] rounded-[8px] border
|
||||
border-solid border-[#EFEFEF] bg-[#FFF] dark:bg-[#222433] dark:border-transparent"
|
||||
key={idx}
|
||||
>
|
||||
<div
|
||||
className={`p-[12px] w-fit h-fit rounded-[2px] ${item.bg_color}`}
|
||||
>
|
||||
{item.icon}
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-[4px]">
|
||||
<p className="text-[#525252] text-[14px] font-normal dark:text-[#D7D8ED]">
|
||||
{item.text}
|
||||
</p>
|
||||
<TextLoading width={70} height={20} loading={loading}>
|
||||
<p className="text-[#3B3B3B] text-[24px] font-medium dark:text-[#A1A1A1]">
|
||||
{item.value}
|
||||
<span className="text-[#616161] mr-[6px] text-[12px] font-normal dark:text-[#A1A1A1]">
|
||||
{item.label}
|
||||
</span>
|
||||
</p>
|
||||
</TextLoading>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
export default Cards;
|
||||
@@ -1,90 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { LineChart, lineElementClasses } from "@mui/x-charts";
|
||||
|
||||
function Chart({ data, loading }) {
|
||||
return (
|
||||
<LineChart
|
||||
loading={loading}
|
||||
xAxis={[
|
||||
{
|
||||
data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
||||
disableLine: true,
|
||||
disableTicks: true,
|
||||
},
|
||||
]}
|
||||
series={[
|
||||
{
|
||||
id: "income",
|
||||
data: data.chart_amount_income,
|
||||
area: true,
|
||||
showMark: false,
|
||||
},
|
||||
]}
|
||||
yAxis={[
|
||||
{
|
||||
disableLine: true,
|
||||
disableTicks: true,
|
||||
},
|
||||
]}
|
||||
margin={{
|
||||
left: 60,
|
||||
right: 50,
|
||||
top: 10,
|
||||
bottom: 60,
|
||||
}}
|
||||
sx={{
|
||||
[`& .${lineElementClasses.root}`]: {
|
||||
strokeWidth: 3,
|
||||
stroke: loading ? "#E6E6E6" : "#5559CE",
|
||||
},
|
||||
"& .MuiAreaElement-series-income": {
|
||||
fill: "url('#myGradient') !important",
|
||||
},
|
||||
"& .MuiChartsAxis-directionY .MuiChartsAxis-tickLabel": {
|
||||
fontSize: "14px !important",
|
||||
fontWeight: "400 !important",
|
||||
fill: "#858D9D",
|
||||
"@media (prefers-color-scheme: dark)": {
|
||||
fill: "#A1A1A1",
|
||||
},
|
||||
},
|
||||
"& .MuiChartsAxis-directionX .MuiChartsAxis-tickLabel": {
|
||||
fontSize: "10px !important",
|
||||
fontWeight: "400 !important",
|
||||
fill: "#7E7E7E",
|
||||
"@media (prefers-color-scheme: dark)": {
|
||||
fill: "#A1A1A1",
|
||||
},
|
||||
},
|
||||
"& .MuiChartsGrid-line": {
|
||||
strokeDasharray: 2,
|
||||
"@media (prefers-color-scheme: dark)": {
|
||||
stroke: "#343645",
|
||||
},
|
||||
},
|
||||
"& .MuiChartsAxis-directionY": {
|
||||
// transform: 'translateX(-50px) !important'
|
||||
},
|
||||
}}
|
||||
grid={{ horizontal: true }}
|
||||
className="!w-full !mt-[20px] !h-[250px]"
|
||||
>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="myGradient"
|
||||
x1="252.5"
|
||||
y1="0"
|
||||
x2="252.5"
|
||||
y2="145"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#3A6FF8" stopOpacity="0.1" />
|
||||
<stop offset="1" stopColor="#3A6FF8" stopOpacity="0.02" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</LineChart>
|
||||
);
|
||||
}
|
||||
|
||||
export default Chart;
|
||||
@@ -1,65 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import ArrowDownP from "@/components/icons/ArrowDownP";
|
||||
import { MenuItem, Select } from "@mui/material";
|
||||
|
||||
function Head() {
|
||||
const list = [
|
||||
{ id: 1, text: "سال 1402" },
|
||||
{ id: 2, text: "سال 1403" },
|
||||
{ id: 3, text: "سال 1404" },
|
||||
{ id: 4, text: "سال 1405" },
|
||||
{ id: 5, text: "سال 1406" },
|
||||
{ id: 6, text: "سال 1407" },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-start gap-[12px] p-[16px]">
|
||||
<p className="text-[#525252] text-[14px] md:text-[16px] font-bold dark:text-[#D7D8ED]">
|
||||
میزان درآمد
|
||||
</p>
|
||||
<Select
|
||||
defaultValue={1}
|
||||
className="!text-[#7E7E7E] dark:!text-[#A1A1A1] !text-[12px] !font-normal !rounded-[4px] dark:!bg-[#222433]"
|
||||
IconComponent={(e) => <ArrowDownP data={e} />}
|
||||
MenuProps={{
|
||||
PaperProps: {
|
||||
className: "dark:!bg-[#222433]",
|
||||
},
|
||||
}}
|
||||
sx={{
|
||||
"& .MuiSelect-select": {
|
||||
padding: "8px 6px 8px 8px !important",
|
||||
},
|
||||
"&:hover": {
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
border: "1px solid #D7D7D7",
|
||||
"@media (prefers-color-scheme: dark)": {
|
||||
borderColor: "#343645 !important",
|
||||
},
|
||||
},
|
||||
},
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
borderColor: "#D7D7D7 !important",
|
||||
border: "1px solid #D7D7D7",
|
||||
"@media (prefers-color-scheme: dark)": {
|
||||
borderColor: "#343645 !important",
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
{list.map((item, idx) => (
|
||||
<MenuItem
|
||||
value={item.id}
|
||||
key={idx}
|
||||
className="dark:!bg-[#222433] dark:!text-[#D7D8ED]"
|
||||
>
|
||||
{item.text}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Head;
|
||||
@@ -1,15 +0,0 @@
|
||||
import Chart from "./Chart";
|
||||
import Head from "./Head";
|
||||
|
||||
function AmountOfIncome({ data, loading }) {
|
||||
return (
|
||||
<div className="rounded-[8px] border border-solid border-[#EFEFEF] bg-[#FFF] dark:bg-[#222433] dark:!border-transparent">
|
||||
<Head />
|
||||
<div dir="ltr">
|
||||
<Chart data={data} loading={loading} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AmountOfIncome;
|
||||
@@ -1,31 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import Activities from "@/components/layoutPanel/userDetail/Activities";
|
||||
import AmountOfIncome from "./amountOfIncome";
|
||||
import Cards from "./Cards";
|
||||
import List from "./list";
|
||||
|
||||
function DashboardPage({ data }) {
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
setLoading(false);
|
||||
}, 2000);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex mt-[4px] flex-col gap-[20px] opacity-page">
|
||||
<Cards data={data} loading={loading} />
|
||||
<List data={data} loading={loading} />
|
||||
<AmountOfIncome data={data} loading={loading} />
|
||||
<div className="flex xl:hidden">
|
||||
<Activities data={data} loading={loading} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DashboardPage;
|
||||
@@ -1,84 +0,0 @@
|
||||
import CustomTable from "@/app/component/CustomTable";
|
||||
import CircularLoading from "@/app/component/loading/Circular";
|
||||
import TextLoading from "@/app/component/loading/Text";
|
||||
import { TableCell, TableRow } from "@mui/material";
|
||||
import Image from "next/image";
|
||||
|
||||
function Table({ data, loading }) {
|
||||
const tableHead = ["ردیف", "نام پزشک", "تخصص", "تاریخ", "ساعت", "تعدد نوبت"];
|
||||
const centerTable = [0, 4];
|
||||
|
||||
return (
|
||||
<div className="hidden md:flex">
|
||||
<CustomTable
|
||||
zeroRadius={true}
|
||||
tableHead={tableHead}
|
||||
centerTable={centerTable}
|
||||
>
|
||||
{data.list_of_doctors_appointments.map((row, idx) => (
|
||||
<TableRow
|
||||
key={idx}
|
||||
className="!border-0 !border-b !border-[#DBDBDB] dark:!border-transparent"
|
||||
>
|
||||
<TableCell
|
||||
className="!pr-[18px] dark:!border-transparent !text-[#616161] dark:!text-[#A1A1A1] !text-[16px] !font-medium !text-nowrap"
|
||||
align="center"
|
||||
>
|
||||
<TextLoading width={15} height={18} loading={loading}>
|
||||
{idx + 1}
|
||||
</TextLoading>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="!pr-[18px] dark:!border-transparent !text-[#616161] dark:!text-[#A1A1A1] !text-[16px] !font-medium !text-nowrap"
|
||||
component="th"
|
||||
scope="row"
|
||||
>
|
||||
<div className="flex items-center justify-start gap-[8px] !text-nowrap">
|
||||
<CircularLoading width={32} height={32} loading={loading}>
|
||||
<Image src={row.image} alt="doctor" height={32} width={32} />
|
||||
</CircularLoading>
|
||||
<TextLoading width={40} height={18} loading={loading}>
|
||||
{row.name}
|
||||
</TextLoading>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="!text-start dark:!border-transparent !text-[#616161] dark:!text-[#A1A1A1] !text-[16px] !font-medium !pr-[18px] !text-nowrap"
|
||||
align="right"
|
||||
>
|
||||
<TextLoading width={30} height={18} loading={loading}>
|
||||
{row.expertise}
|
||||
</TextLoading>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="!text-start dark:!border-transparent !text-[#616161] dark:!text-[#A1A1A1] !text-[16px] !font-medium !pr-[18px] !text-nowrap"
|
||||
align="right"
|
||||
>
|
||||
<TextLoading width={50} height={18} loading={loading}>
|
||||
{row.date}
|
||||
</TextLoading>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="!text-center dark:!border-transparent !text-[#616161] dark:!text-[#A1A1A1] !text-[16px] !font-medium !pr-[18px] !text-nowrap"
|
||||
align="right"
|
||||
>
|
||||
<TextLoading width={50} height={18} loading={loading}>
|
||||
{row.hour}
|
||||
</TextLoading>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="!text-right dark:!border-transparent !text-[#616161] dark:!text-[#A1A1A1] !text-[16px] !font-medium !pr-[18px] !text-nowrap"
|
||||
align="right"
|
||||
>
|
||||
<TextLoading width={50} height={18} loading={loading}>
|
||||
{row.number_of_turns}
|
||||
</TextLoading>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</CustomTable>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Table;
|
||||
@@ -1,29 +0,0 @@
|
||||
import { Button } from "@mui/material";
|
||||
import ArrowLeftP from "../../../icons/ArrowLeftP";
|
||||
import Table from "./Table";
|
||||
import ColTable from "../../ColTable";
|
||||
|
||||
function List({ data, loading }) {
|
||||
return (
|
||||
<div className="rounded-[8px] border overflow-hidden border-solid w-full border-transparent md:border-[#EFEFEF] bg-transparent md:bg-[#FFF] dark:bg-transparent md:dark:bg-[#222433] dark:border-transparent">
|
||||
<div className="items-center justify-between p-[16px] flex">
|
||||
<p className="text-[#525252] text-[14px] md:text-[16px] font-bold dark:text-[#D7D8ED]">
|
||||
لیست نوبت های پزشکان
|
||||
</p>
|
||||
<Button
|
||||
variant="text"
|
||||
className="!hidden md:!flex !items-center !justify-center !text-[#616161] !text-[14px] !font-normal !gap-[4px] !p-1 dark:!text-[#A1A1A1]"
|
||||
>
|
||||
مشاهده همه
|
||||
<ArrowLeftP />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="w-full overflow-auto">
|
||||
<Table data={data} loading={loading} />
|
||||
<ColTable data={data.list_of_doctors_appointments} loading={loading} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default List;
|
||||
@@ -1,14 +0,0 @@
|
||||
import FilterDate from "./FilterDate";
|
||||
|
||||
function Date() {
|
||||
return (
|
||||
<div className="flex items-center justify-start gap-y-[20px] gap-[8px] md:gap-0">
|
||||
<p className="text-[#616161] text-[14px] font-normal md:hidden dark:text-[#a1a1a1]">
|
||||
انتخاب بازه زمانی
|
||||
</p>
|
||||
<FilterDate />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Date;
|
||||
@@ -1,37 +0,0 @@
|
||||
import { useState } from "react";
|
||||
import { convertToJalali } from "@/helper";
|
||||
import { ButtonGroup } from "@mui/material";
|
||||
import PopoverDate from "@/app/component/PopoverDate";
|
||||
|
||||
function FilterDate() {
|
||||
const [date, setDate] = useState({
|
||||
start: null,
|
||||
end: null,
|
||||
});
|
||||
|
||||
const updateDate = (newDate, type) => {
|
||||
setDate({
|
||||
...date,
|
||||
[type]: newDate,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<ButtonGroup variant="outlined">
|
||||
<PopoverDate
|
||||
type="start"
|
||||
date={date.start}
|
||||
updateDate={updateDate}
|
||||
text={date.start ? convertToJalali(date.start) : "از تاریخ"}
|
||||
/>
|
||||
<PopoverDate
|
||||
type="end"
|
||||
date={date.end}
|
||||
updateDate={updateDate}
|
||||
text={date.end ? convertToJalali(date.end) : "تا تاریخ"}
|
||||
/>
|
||||
</ButtonGroup>
|
||||
);
|
||||
}
|
||||
|
||||
export default FilterDate;
|
||||
@@ -1,53 +0,0 @@
|
||||
import ArrowBottomP from "@/components/icons/ArrowBottomP";
|
||||
import ExportP from "@/components/icons/ExportP";
|
||||
import SearchD from "@/components/icons/SearchD";
|
||||
import { Button, ButtonGroup, TextField } from "@mui/material";
|
||||
|
||||
function SearchDoctor() {
|
||||
return (
|
||||
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-y-[20px] justify-between mt-[20px] md:mt-[22px] lg:mt-[24px] ">
|
||||
<ButtonGroup
|
||||
variant="contained"
|
||||
className="lg:!w-[55%] !rounded-[4px] !overflow-hidden
|
||||
flex items-center !shadow-none !h-fit !p-1 !border !border-[#EFEFEF] dark:!border-[#343645]"
|
||||
>
|
||||
<TextField
|
||||
variant="standard"
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
}}
|
||||
sx={{
|
||||
background: "transparent !important",
|
||||
"& .MuiInputBase-root": { height: "100%" },
|
||||
"& .MuiInput-root": { borderBottom: "none" },
|
||||
"& .MuiInputBase-input": {
|
||||
// background: "red !important",
|
||||
color: "#7E7E7E",
|
||||
padding: "0",
|
||||
},
|
||||
}}
|
||||
placeholder="جستجو براساس نام پزشک..."
|
||||
dir="rtl"
|
||||
className={`!shadow-none !w-full !px-5 !h-full !text-[14px] md:!text-[16px] !min-w-[50%] !rounded-0 !font-normal !text-[#6C757D]`}
|
||||
/>
|
||||
<Button
|
||||
className="
|
||||
!rounded-[4px] !p-[8px] !w-[56px] !h-[56px] !max-w-[40px] !max-h-[40px]
|
||||
"
|
||||
>
|
||||
<SearchD />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<Button
|
||||
variant="outlined"
|
||||
className="!border-[#5559CE] dark:!bg-[#C7CEF4] dark:!text-[#5559CE] !flex !text-[14px] md:!text-[16px] !items-center !gap-[4px] md:!gap-[5px] lg:!gap-[6px] !rounded-[4px] !py-[8px] md:!py-[9px] !px-[12px] sm:!px-[14px] md:!px-[16px] lg:!px-[18px]"
|
||||
>
|
||||
<ExportP />
|
||||
خروجی گرفتن
|
||||
<ArrowBottomP />
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SearchDoctor;
|
||||
@@ -1,18 +0,0 @@
|
||||
import Date from "./Date";
|
||||
import SearchDoctor from "./SearchDoctor";
|
||||
|
||||
function Head() {
|
||||
return (
|
||||
<div className="w-full">
|
||||
<div className="flex flex-col sm:flex-row items-start md:items-center justify-start gap-[10px]">
|
||||
<p className="text-[#525252] dark:text-[#D7D8ED] text-[14px] sm:text-[16px] md:text-[18px] lg:text-[20px] font-bold">
|
||||
لیست نوبت های پزشکان
|
||||
</p>
|
||||
<Date />
|
||||
</div>
|
||||
<SearchDoctor />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Head;
|
||||
@@ -1,25 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import Head from "./head";
|
||||
import List from "./list";
|
||||
|
||||
function TurnsPage({ data }) {
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
setLoading(false);
|
||||
}, 2000);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="bg-transparent dark:shadow-[0px_4px_25px_10px_#1F1D2B] md:dark:bg-[#222433] md:bg-[#FFF] opacity-page rounded-[8px] shadow-none md:shadow-[0px_1px_24.8px_0px_rgba(204,204,204,0.18)] pt-0 md:pt-[12px] lg:pt-[24px] px-0 md:px-[24px] p-[24px]">
|
||||
<Head />
|
||||
<List data={data} loading={loading} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default TurnsPage;
|
||||
@@ -1,7 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
function Cards() {
|
||||
return <div className="flex hidden">Cards</div>;
|
||||
}
|
||||
|
||||
export default Cards;
|
||||
@@ -1,83 +0,0 @@
|
||||
import Image from "next/image";
|
||||
|
||||
import { TableCell, TableRow } from "@mui/material";
|
||||
import Pagination from "@/app/component/Pagination";
|
||||
import CustomTable from "@/app/component/CustomTable";
|
||||
import TextLoading from "@/app/component/loading/Text";
|
||||
import CustomLoading from "@/app/component/loading/Custom";
|
||||
import CircularLoading from "@/app/component/loading/Circular";
|
||||
|
||||
function Table({ data, loading }) {
|
||||
const tableHead = ["ردیف", "نام پزشک", "تخصص", "تاریخ", "ساعت", "تعدد نوبت"];
|
||||
const centerTable = [0, 4];
|
||||
|
||||
return (
|
||||
<div className="hidden md:flex flex-col">
|
||||
<CustomTable tableHead={tableHead} centerTable={centerTable}>
|
||||
{data.list_of_doctors_appointments.map((row, idx) => (
|
||||
<TableRow key={idx} className="!border-0 !border-b !border-[#DBDBDB]">
|
||||
<TableCell
|
||||
className="!text-[#616161] dark:!text-[#A1A1A1] !text-[16px] !font-medium !pr-[18px] !text-nowrap"
|
||||
align="center"
|
||||
>
|
||||
<TextLoading width={15} height={18} loading={loading}>
|
||||
{idx + 1}
|
||||
</TextLoading>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="!text-[#616161] dark:!text-[#A1A1A1] !text-[16px] !font-medium !pr-[18px] !text-nowrap"
|
||||
component="th"
|
||||
scope="row"
|
||||
>
|
||||
<div className="flex items-center justify-start gap-[8px] !text-nowrap">
|
||||
<CircularLoading width={32} height={32} loading={loading}>
|
||||
<Image src={row.image} alt="doctor" height={32} width={32} />
|
||||
</CircularLoading>
|
||||
<TextLoading width={40} height={18} loading={loading}>
|
||||
{row.name}
|
||||
</TextLoading>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="!text-[#616161] dark:!text-[#A1A1A1] !text-[16px] !font-medium !text-start !pr-[18px] !text-nowrap"
|
||||
align="right"
|
||||
>
|
||||
<TextLoading width={50} height={18} loading={loading}>
|
||||
{row.expertise}
|
||||
</TextLoading>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="!text-[#616161] dark:!text-[#A1A1A1] !text-[16px] !font-medium !text-start !pr-[18px] !text-nowrap"
|
||||
align="left"
|
||||
>
|
||||
<TextLoading width={50} height={18} loading={loading}>
|
||||
{row.date}
|
||||
</TextLoading>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="!text-[#616161] dark:!text-[#A1A1A1] !text-[16px] !font-medium !text-center !pr-[18px] !text-nowrap"
|
||||
align="right"
|
||||
>
|
||||
<TextLoading width={50} height={18} loading={loading}>
|
||||
{row.hour}
|
||||
</TextLoading>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="!text-[#616161] dark:!text-[#A1A1A1] !text-[16px] !font-medium !pr-[18px] !text-nowrap"
|
||||
align="left"
|
||||
>
|
||||
<CustomLoading width={80} height={22} loading={loading}>
|
||||
{row.number_of_turns}
|
||||
</CustomLoading>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</CustomTable>
|
||||
<div className="w-full flex justify-center mt-[48px]">
|
||||
<Pagination />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Table;
|
||||
@@ -1,13 +0,0 @@
|
||||
import ColTable from "../../ColTable";
|
||||
import Table from "./Table";
|
||||
|
||||
function List({ data, loading }) {
|
||||
return (
|
||||
<div className="mt-[32px] pb-[20px] table-rounded-8">
|
||||
<Table data={data} loading={loading} />
|
||||
<ColTable data={data.list_of_doctors_appointments} loading={loading} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default List;
|
||||
@@ -1,35 +0,0 @@
|
||||
import Tabs from "@/app/component/Tabs";
|
||||
|
||||
function Tab({ value, listTab, handleChange }) {
|
||||
return (
|
||||
<Tabs
|
||||
isSm={false}
|
||||
style={{
|
||||
".MuiTabs-indicator": {
|
||||
height: "2px",
|
||||
borderRadius: "16px",
|
||||
background: "#5559CE",
|
||||
},
|
||||
"& .MuiTabs-flexContainer": {
|
||||
borderBottom: "2px solid #EFEFEF",
|
||||
},
|
||||
"& .mui-11pdt05-MuiButtonBase-root-MuiTab-root.Mui-selected": {
|
||||
color: "#5559CE !important",
|
||||
},
|
||||
"& .MuiButtonBase-root": {
|
||||
fontWeight: "400 !important",
|
||||
},
|
||||
"& .MuiButtonBase-root.Mui-selected": {
|
||||
color: "#5559CE !important",
|
||||
fontWeight: "700 !important",
|
||||
transition: "0.3s all !important",
|
||||
},
|
||||
}}
|
||||
value={value}
|
||||
listTab={listTab}
|
||||
handleChange={handleChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default Tab;
|
||||
@@ -1,12 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import UploadFile from "@/app/component/uploadFile";
|
||||
import { useState } from "react";
|
||||
|
||||
function Head() {
|
||||
const [image, setImage] = useState("");
|
||||
|
||||
return <UploadFile image={image} setImage={setImage} />;
|
||||
}
|
||||
|
||||
export default Head;
|
||||
@@ -1,157 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
|
||||
import ContentText from "../../../../../app/component/ContentText";
|
||||
import EditField from "@/app/component/fields/EditField";
|
||||
import AutoCompleteSelect from "@/app/component/element/AutoCompleteSelect";
|
||||
import { bank, city, state } from "./listSelector";
|
||||
import AddLocationP from "@/components/icons/AddLocationP";
|
||||
import { Button } from "@mui/material";
|
||||
import ArrowLeftButtonP from "@/components/icons/ArrowLeftButtonP";
|
||||
|
||||
const validate_phone_number = {
|
||||
min: 1,
|
||||
max: 9999999999,
|
||||
};
|
||||
|
||||
function Form() {
|
||||
const [data, setData] = useState({
|
||||
name: { value: "", isEdit: true },
|
||||
national_code: { value: "", isEdit: true },
|
||||
address: { value: "", isEdit: true },
|
||||
phone: { value: "", isEdit: true },
|
||||
account_number: { value: "", isEdit: true },
|
||||
});
|
||||
const [selected, setSelected] = useState({
|
||||
state: "",
|
||||
city: "",
|
||||
bank: "",
|
||||
});
|
||||
const updateSelect = (event, name) =>
|
||||
setSelected({ ...selected, [name]: event });
|
||||
|
||||
const changeData = (value, type, name) =>
|
||||
setData({
|
||||
...data,
|
||||
[name]: {
|
||||
...data[name],
|
||||
[type]: value,
|
||||
},
|
||||
});
|
||||
|
||||
const updateNum = (value, type, name) => {
|
||||
const parseValue = +value;
|
||||
const { max } = validate_phone_number;
|
||||
const validateValue = parseValue > max ? data[name].value : value;
|
||||
changeData(validateValue, type, name);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-start justify-start mt-[24px] md:mt-[28px] lg:mt-[32px] gap-[32px] md:gap-[40px] lg:gap-[48px]">
|
||||
<ul className="grid w-full grid-cols-1 md:grid-cols-2 gap-x-[48px] gap-y-[24px] md:gap-y-[28px] lg:gap-y-[32px]">
|
||||
<ContentText text="نام و نام خانوادگی">
|
||||
<EditField
|
||||
isTransparent={true}
|
||||
iconGray={true}
|
||||
changeData={changeData}
|
||||
data={data?.name}
|
||||
name="name"
|
||||
/>
|
||||
</ContentText>
|
||||
<ContentText text="کد ملی">
|
||||
<EditField
|
||||
isTransparent={true}
|
||||
iconGray={true}
|
||||
changeData={updateNum}
|
||||
data={data?.national_code}
|
||||
noDisable={true}
|
||||
type="number"
|
||||
placeholder="کد ملی"
|
||||
name="national_code"
|
||||
props={{
|
||||
inputProps: validate_phone_number,
|
||||
}}
|
||||
/>
|
||||
</ContentText>
|
||||
<ContentText text="استان">
|
||||
<AutoCompleteSelect
|
||||
updateData={updateSelect}
|
||||
label="انتخاب کنید..."
|
||||
name="state"
|
||||
list={state}
|
||||
/>
|
||||
</ContentText>
|
||||
<ContentText text="شهر">
|
||||
<AutoCompleteSelect
|
||||
updateData={updateSelect}
|
||||
label="انتخاب کنید..."
|
||||
name="city"
|
||||
list={city}
|
||||
/>
|
||||
</ContentText>
|
||||
<ContentText text="آدرس">
|
||||
<EditField
|
||||
icon={<AddLocationP />}
|
||||
isTransparent={true}
|
||||
placeholder="از روی نقشه انتخاب کنید..."
|
||||
iconGray={true}
|
||||
changeData={changeData}
|
||||
data={data?.address}
|
||||
name="address"
|
||||
/>
|
||||
</ContentText>
|
||||
<ContentText text="شماره موبایل">
|
||||
<EditField
|
||||
isTransparent={true}
|
||||
iconGray={true}
|
||||
changeData={updateNum}
|
||||
data={data?.phone}
|
||||
noDisable={true}
|
||||
type="number"
|
||||
placeholder="شماره موبایل"
|
||||
name="phone"
|
||||
props={{
|
||||
inputProps: validate_phone_number,
|
||||
}}
|
||||
/>
|
||||
</ContentText>
|
||||
<ContentText text="شماره حساب">
|
||||
<EditField
|
||||
isTransparent={true}
|
||||
iconGray={true}
|
||||
changeData={updateNum}
|
||||
data={data?.account_number}
|
||||
noDisable={true}
|
||||
type="number"
|
||||
placeholder="شماره حساب"
|
||||
name="account_number"
|
||||
props={{
|
||||
inputProps: validate_phone_number,
|
||||
}}
|
||||
/>
|
||||
</ContentText>
|
||||
<ContentText text="بانک">
|
||||
<AutoCompleteSelect
|
||||
updateData={updateSelect}
|
||||
label="انتخاب کنید..."
|
||||
name="bank"
|
||||
list={bank}
|
||||
/>
|
||||
</ContentText>
|
||||
</ul>
|
||||
<div className="w-full flex justify-end">
|
||||
<Button
|
||||
variant="contained"
|
||||
className="!gap-[4px] !py-[8px] !px-[24px] !rounded-[4px] !w-full md:!w-fit
|
||||
!shadow-none !text-[#EFEFEF] !text-[14px] md:!text-[16px] !font-medium"
|
||||
>
|
||||
ثبت اطلاعات
|
||||
<ArrowLeftButtonP />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Form;
|
||||
@@ -1,20 +0,0 @@
|
||||
export const state = [
|
||||
{ label: "استان 1", id: 10 },
|
||||
{ label: "استان 2", id: 20 },
|
||||
{ label: "استان 3", id: 30 },
|
||||
{ label: "استان 4", id: 40 },
|
||||
];
|
||||
|
||||
export const city = [
|
||||
{ label: "شهر 1", id: 10 },
|
||||
{ label: "شهر 2", id: 20 },
|
||||
{ label: "شهر 3", id: 30 },
|
||||
{ label: "شهر 4", id: 40 },
|
||||
];
|
||||
|
||||
export const bank = [
|
||||
{ label: "بانک 1", id: 10 },
|
||||
{ label: "بانک 2", id: 20 },
|
||||
{ label: "بانک 3", id: 30 },
|
||||
{ label: "بانک 4", id: 40 },
|
||||
];
|
||||
@@ -1,13 +0,0 @@
|
||||
import Form from "./form";
|
||||
import Head from "./Head";
|
||||
|
||||
function Account() {
|
||||
return (
|
||||
<div className="opacity-page">
|
||||
<Head />
|
||||
<Form />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Account;
|
||||
@@ -1,91 +0,0 @@
|
||||
import CustomTable from "@/app/component/CustomTable";
|
||||
import { Button, TableCell, TableRow } from "@mui/material";
|
||||
import TextLoading from "@/app/component/loading/Text";
|
||||
import TrashB from "@/components/icons/TrashB";
|
||||
import EditB from "@/components/icons/EditB";
|
||||
import SwitchTable from "@/app/component/SwitchTable";
|
||||
|
||||
function List({ data, loading, changeStatus }) {
|
||||
const tableHead = ["ردیف", "شماره کارت", "شماره شبا", "بانک", "وضعیت", ""];
|
||||
const centerTable = [0, 4, 5];
|
||||
|
||||
return (
|
||||
<div className="!mt-[40px] hidden md:block">
|
||||
<div className="hidden md:block w-full">
|
||||
<CustomTable tableHead={tableHead} centerTable={centerTable}>
|
||||
{data.map((row, idx) => (
|
||||
<TableRow
|
||||
key={idx}
|
||||
className="!border-0 !border-b !border-[#DBDBDB]"
|
||||
>
|
||||
<TableCell
|
||||
className="!pr-[18px] !bg-[#F8F8F8] dark:!bg-transparent dark:!text-[#A1A1A1] !text-[16px] !font-medium !text-[#616161] !text-nowrap"
|
||||
align="center"
|
||||
>
|
||||
<TextLoading width={15} height={18} loading={loading}>
|
||||
{idx + 1}
|
||||
</TextLoading>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="!text-start !bg-[#F8F8F8] dark:!bg-transparent dark:!text-[#A1A1A1] !text-[16px] !font-medium !text-[#616161] !pr-[18px] !text-nowrap"
|
||||
align="right"
|
||||
>
|
||||
<TextLoading width={50} height={18} loading={loading}>
|
||||
{row.card_number}
|
||||
</TextLoading>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="!text-start !bg-[#F8F8F8] dark:!bg-transparent dark:!text-[#A1A1A1] !text-[16px] !font-medium !text-[#616161] !pr-[18px] !text-nowrap"
|
||||
align="right"
|
||||
>
|
||||
<TextLoading width={80} height={18} loading={loading}>
|
||||
{row.shaba_number}
|
||||
</TextLoading>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="!text-start !bg-[#F8F8F8] dark:!bg-transparent dark:!text-[#A1A1A1] !text-[16px] !font-medium !text-[#616161] !pr-[18px] !text-nowrap"
|
||||
align="right"
|
||||
>
|
||||
<TextLoading width={30} height={18} loading={loading}>
|
||||
{row.bank}
|
||||
</TextLoading>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="!text-start !bg-[#F8F8F8] dark:!bg-transparent dark:!text-[#A1A1A1] !pr-[18px] !text-nowrap"
|
||||
align="right"
|
||||
>
|
||||
<TextLoading width={50} height={18} loading={loading}>
|
||||
<div className="flex items-center justify-start gap-[16px]">
|
||||
<p className="text-[16px] min-w-[60px] dark:text-[#A1A1A1] font-medium text-[#616161]">
|
||||
{row.status ? "فعال" : "غیر فعال"}
|
||||
</p>
|
||||
<SwitchTable
|
||||
id={row.id}
|
||||
value={row.status}
|
||||
changeStatus={changeStatus}
|
||||
/>
|
||||
</div>
|
||||
</TextLoading>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="!text-center !bg-[#F8F8F8] dark:!bg-transparent dark:!text-[#A1A1A1] !pr-[18px] !text-nowrap"
|
||||
align="right"
|
||||
>
|
||||
<div className="flex items-center justify-center gap-[4px]">
|
||||
<Button className="!min-w-fit !p-1" variant="text">
|
||||
<TrashB />
|
||||
</Button>
|
||||
<Button className="!min-w-fit !p-1" variant="text">
|
||||
<EditB />
|
||||
</Button>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</CustomTable>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default List;
|
||||
@@ -1,78 +0,0 @@
|
||||
import TextLoading from "@/app/component/loading/Text";
|
||||
import SwitchTable from "@/app/component/SwitchTable";
|
||||
import EditB from "@/components/icons/EditB";
|
||||
import TrashB from "@/components/icons/TrashB";
|
||||
import { Button } from "@mui/material";
|
||||
|
||||
function Item({ data, loading, changeStatus }) {
|
||||
return (
|
||||
<li className="rounded-[8px] bg-[#FFF] p-[12px] dark:shadow-transparent dark:bg-[#222433] shadow-[0px_1px_24.8px_0px_rgba(204,_204,_204,_0.18)]">
|
||||
<div className="w-full flex items-center justify-between">
|
||||
<div className="flex items-center justify-start gap-[4px]">
|
||||
<TextLoading width={50} height={18} loading={loading}>
|
||||
<div className="flex items-center justify-start gap-[16px]">
|
||||
<p className="text-[16px] min-w-[60px] font-medium text-[#616161] dark:text-[#A1A1A1]">
|
||||
{data.status ? "فعال" : "غیر فعال"}
|
||||
</p>
|
||||
<SwitchTable
|
||||
id={data.id}
|
||||
value={data.status}
|
||||
changeStatus={changeStatus}
|
||||
/>
|
||||
</div>
|
||||
</TextLoading>
|
||||
</div>
|
||||
<div className="flex items-center justify-center gap-[4px]">
|
||||
<Button className="!min-w-fit !p-1" variant="text">
|
||||
<TrashB />
|
||||
</Button>
|
||||
<Button className="!min-w-fit !p-1" variant="text">
|
||||
<EditB />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<ul className="flex flex-col mt-[16px]">
|
||||
<li className="flex items-center justify-between gap-[12px]">
|
||||
<TextLoading loading={loading} width={60} height={18}>
|
||||
<p className="text-[#7E7E7E] text-[14px] font-normal dark:text-[#A1A1A1]">
|
||||
شماره کارت:
|
||||
</p>
|
||||
</TextLoading>
|
||||
<TextLoading loading={loading} width={90} height={18}>
|
||||
<p className="text-[#616161] text-[12px] font-medium dark:text-[#A1A1A1]">
|
||||
{data.card_number}
|
||||
</p>
|
||||
</TextLoading>
|
||||
</li>
|
||||
<span className="block h-px w-[calc(100%-20px)] dark:bg-[#343645] mx-auto bg-[#EFEFEF] my-[8px]"></span>
|
||||
<li className="flex items-center justify-between gap-[12px]">
|
||||
<TextLoading loading={loading} width={60} height={18}>
|
||||
<p className="text-[#7E7E7E] text-[14px] font-normal dark:text-[#A1A1A1]">
|
||||
شماره شبا:
|
||||
</p>
|
||||
</TextLoading>
|
||||
<TextLoading loading={loading} width={90} height={18}>
|
||||
<p className="text-[#616161] text-[12px] font-medium dark:text-[#A1A1A1]">
|
||||
{data.shaba_number}
|
||||
</p>
|
||||
</TextLoading>
|
||||
</li>
|
||||
<span className="block h-px w-[calc(100%-20px)] mx-auto bg-[#EFEFEF] my-[8px] dark:bg-[#343645]"></span>
|
||||
<li className="flex items-center justify-between gap-[12px]">
|
||||
<TextLoading loading={loading} width={60} height={18}>
|
||||
<p className="text-[#7E7E7E] text-[14px] font-normal dark:text-[#A1A1A1]">
|
||||
بانک:
|
||||
</p>
|
||||
</TextLoading>
|
||||
<TextLoading loading={loading} width={90} height={18}>
|
||||
<p className="text-[#616161] text-[12px] font-medium dark:text-[#A1A1A1]">
|
||||
{data.bank}
|
||||
</p>
|
||||
</TextLoading>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
export default Item;
|
||||
@@ -1,13 +0,0 @@
|
||||
import Item from "./Item";
|
||||
|
||||
function Cards({ data, loading, changeStatus }) {
|
||||
return (
|
||||
<ul className="md:hidden mt-[24px] grid grid-cols-1 sm:grid-cols-2 gap-[16px]">
|
||||
{data.map((item, idx) => (
|
||||
<Item data={item} key={idx} changeStatus={changeStatus} />
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
export default Cards;
|
||||
@@ -1,14 +0,0 @@
|
||||
import ModalAddCard from "./modal";
|
||||
|
||||
function Head() {
|
||||
return (
|
||||
<div className="w-full flex items-center justify-between">
|
||||
<p className="text-[#525252] dark:text-[#A1A1A1] text-[20px] font-bold">
|
||||
کارت های بانکی شما
|
||||
</p>
|
||||
<ModalAddCard />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Head;
|
||||
@@ -1,58 +0,0 @@
|
||||
import EditField from "@/app/component/fields/EditField";
|
||||
import ContentText from "@/app/component/ContentText";
|
||||
import AutoCompleteSelect from "@/app/component/element/AutoCompleteSelect";
|
||||
import { validate_phone_number } from "./validate";
|
||||
|
||||
const list = [
|
||||
{ label: "بانک 1", id: 10 },
|
||||
{ label: "بانک 2", id: 20 },
|
||||
{ label: "بانک 3", id: 30 },
|
||||
{ label: "بانک 4", id: 40 },
|
||||
];
|
||||
|
||||
function Form({ data, changeData, updateNum }) {
|
||||
return (
|
||||
<div className="mt-[32px] md:mt-[36px] lg:mt-[40px] flex flex-col gap-[24px] md:gap-[28px] lg:gap-[32px] px-0 sm:px-[52px]">
|
||||
<ContentText text="شماره کارت">
|
||||
<EditField
|
||||
isTransparent={true}
|
||||
iconGray={true}
|
||||
changeData={updateNum}
|
||||
data={data.card}
|
||||
noDisable={true}
|
||||
type="number"
|
||||
placeholder="شماره کارت خود را بنویسید..."
|
||||
name="card"
|
||||
props={{
|
||||
inputProps: validate_phone_number,
|
||||
}}
|
||||
/>
|
||||
</ContentText>
|
||||
<ContentText text="شماره شبا">
|
||||
<EditField
|
||||
isTransparent={true}
|
||||
iconGray={true}
|
||||
changeData={updateNum}
|
||||
data={data.shaba}
|
||||
noDisable={true}
|
||||
type="number"
|
||||
placeholder="شماره شبا خود را بنویسید..."
|
||||
name="shaba"
|
||||
props={{
|
||||
inputProps: validate_phone_number,
|
||||
}}
|
||||
/>
|
||||
</ContentText>
|
||||
<ContentText text="بانک">
|
||||
<AutoCompleteSelect
|
||||
updateData={changeData}
|
||||
label="انتخاب بانک...."
|
||||
name="bank"
|
||||
list={list}
|
||||
/>
|
||||
</ContentText>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Form;
|
||||
@@ -1,82 +0,0 @@
|
||||
import { useState } from "react";
|
||||
import Form from "./Form";
|
||||
import { styleDefault } from "@/mui";
|
||||
import { Box, Button, Modal } from "@mui/material";
|
||||
|
||||
// Icons
|
||||
import PlusB from "@/components/icons/PlusB";
|
||||
import CloseModalD from "@/components/icons/CloseModalD";
|
||||
|
||||
function ModalAddCard() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [data, setData] = useState({
|
||||
card: { value: "", is_edit: true },
|
||||
shaba: { value: "", is_edit: true },
|
||||
bank: { value: "", is_edit: true },
|
||||
});
|
||||
|
||||
const handleOpen = () => setOpen(true);
|
||||
const handleClose = () => setOpen(false);
|
||||
|
||||
const changeData = (value, name) =>
|
||||
setData({ ...data, [name]: { ...data[name], value } });
|
||||
|
||||
const updateNum = (value, type, name) => {
|
||||
const parseValue = +value;
|
||||
|
||||
changeData(parseValue, name);
|
||||
};
|
||||
|
||||
const isValidData = data.card && data.shaba && data.value && data.value.value;
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Button Modal */}
|
||||
<Button
|
||||
className="!bg-[#5559CE] !w-fit !shadow-none !rounded-[4px] !gap-[4px] !text-[#EFEFEF] !text-[14px] md:!text-[16px] !font-medium"
|
||||
onClick={handleOpen}
|
||||
variant="contained"
|
||||
>
|
||||
<PlusB />
|
||||
اضافه کردن کارت
|
||||
</Button>
|
||||
{/* Content Modal */}
|
||||
<Modal open={open} onClose={handleClose}>
|
||||
<Box
|
||||
sx={styleDefault}
|
||||
className="!w-full dark:!bg-[#222433] dark:!shadow-none !h-full md:!h-fit sm:!w-fit !rounded-none sm:!rounded-[8px] sm:!min-w-[524px] !py-[20px] !pt-[24px] md:!pt-[22px] lg:!pt-[20px] !pb-[36px]"
|
||||
>
|
||||
<div className="flex items-center justify-between w-full">
|
||||
<p className="text-[#3B3B3B] dark:text-[#D7D8ED] text-[16px] md:text-[18px] lg:text-[20px] font-bold">
|
||||
اضافه کردن شماره کارت
|
||||
</p>
|
||||
<Button onClick={handleClose} className="!p-1" variant="text">
|
||||
<CloseModalD />
|
||||
</Button>
|
||||
</div>
|
||||
<Form data={data} changeData={changeData} updateNum={updateNum} />
|
||||
<div className="flex items-center justify-center gap-[12px] md:gap-[14px] lg:gap-[16px] mt-[32px] md:mt-[36px] lg:mt-[40px]">
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={handleClose}
|
||||
className="!min-w-[134px] !rounded-[4px] !h-[40px] md:!h-[44px] lg:!h-[48px] !border-[#828DE0] dark:!bg-[#C7CEF4]
|
||||
dark:!border-transparent dark:!text-[#5559CE] !text-[#828DE0] !text-[16px] !font-medium"
|
||||
>
|
||||
انصراف
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleClose}
|
||||
disabled={!isValidData}
|
||||
className="!min-w-[134px] !rounded-[4px] !h-[40px] md:!h-[44px] lg:!h-[48px] !text-[#EFEFEF] !text-[16px] !font-medium"
|
||||
>
|
||||
ذخیره
|
||||
</Button>
|
||||
</div>
|
||||
</Box>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ModalAddCard;
|
||||
@@ -1,6 +0,0 @@
|
||||
const validate_phone_number = {
|
||||
min: 1,
|
||||
max: 9999999999,
|
||||
};
|
||||
|
||||
export { validate_phone_number };
|
||||
@@ -1,31 +0,0 @@
|
||||
import { useState } from "react";
|
||||
import Cards from "./cards";
|
||||
import Head from "./head";
|
||||
import List from "./List";
|
||||
|
||||
function Bank({ data, loading }) {
|
||||
const [list, setList] = useState(data);
|
||||
|
||||
const changeStatus = (value, id) => {
|
||||
let newList = list;
|
||||
if (value) {
|
||||
newList = newList.map((item, idx) => {
|
||||
return {
|
||||
...item,
|
||||
status: item.id === id ? value : false,
|
||||
};
|
||||
});
|
||||
}
|
||||
setList(newList);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="opacity-page">
|
||||
<Head />
|
||||
<List data={list} loading={loading} changeStatus={changeStatus} />
|
||||
<Cards data={list} loading={loading} changeStatus={changeStatus} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Bank;
|
||||
@@ -1,38 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import Account from "./account";
|
||||
import Bank from "./bank";
|
||||
import Tab from "./Tab";
|
||||
|
||||
const listTab = ["حساب کاربری", "حساب بانکی"];
|
||||
|
||||
function UserAccountPage({ data }) {
|
||||
const [value, setValue] = useState(0);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
setLoading(false);
|
||||
}, 2000);
|
||||
}, []);
|
||||
|
||||
const handleChange = (event, newValue) => setValue(newValue);
|
||||
|
||||
const components = [<Account />, <Bank loading={loading} data={data.bank} />];
|
||||
|
||||
return (
|
||||
<div
|
||||
className="
|
||||
opacity-page rounded-[8px] bg-transparent md:bg-[#FFF] min-h-[80vh]
|
||||
shadow-none md:shadow-[0px_1px_24.8px_0px_rgba(204,204,204,0.18)] py-0 md:py-[7px] lg:py-[14px] lg:!pb-[24px]
|
||||
px-0 sm:px-[18px] md:px-[36px] lg:px-[44px] xl:px-[56px] dark:shadow-[0px_4px_25px_10px_#1F1D2B] dark:bg-transparent md:dark:bg-[#222433]
|
||||
"
|
||||
>
|
||||
<Tab listTab={listTab} handleChange={handleChange} value={value} />
|
||||
<div className="mt-[22px]">{components[value]}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default UserAccountPage;
|
||||
@@ -1,5 +1,4 @@
|
||||
import { AbilityBuilder, createMongoAbility } from "@casl/ability";
|
||||
import { safeJsonParse } from "./sanitize";
|
||||
|
||||
export function defineAbilitiesFor(user) {
|
||||
const { can, cannot, build } = new AbilityBuilder(createMongoAbility);
|
||||
@@ -7,11 +6,6 @@ export function defineAbilitiesFor(user) {
|
||||
if (user) {
|
||||
can("access", "Dashboard");
|
||||
cannot("access", "Login");
|
||||
const parsedData = safeJsonParse(user.value);
|
||||
const roles = parsedData?.roles;
|
||||
if (roles && Array.isArray(Object.values(roles)) && Object.values(roles).includes("representation")) {
|
||||
can("access", "Panel");
|
||||
}
|
||||
} else {
|
||||
can("access", "Login");
|
||||
cannot("access", "Dashboard");
|
||||
|
||||
@@ -1,56 +1,3 @@
|
||||
import moment from "moment-jalaali";
|
||||
|
||||
const DEFAULT_AVATAR = "/assets/images/doctor.png";
|
||||
|
||||
function toJalali(date) {
|
||||
if (!date) return "--";
|
||||
return moment(date).format("jYYYY/jM/jD");
|
||||
}
|
||||
|
||||
export function adaptRepresentationInfo(representationInfo) {
|
||||
const data = representationInfo?.data ?? representationInfo ?? {};
|
||||
|
||||
return {
|
||||
name: data.full_name ?? "",
|
||||
src: data.avatar ?? DEFAULT_AVATAR,
|
||||
detail: data.city_name ? `نماینده شهر ${data.city_name}` : "نماینده",
|
||||
mobile_number: data.mobile_number ?? "",
|
||||
commission_percent: data.commission_percent ?? null,
|
||||
bank_account: data.bank_account ?? null,
|
||||
city: { label: data.city_name ?? "" },
|
||||
all_patients: null,
|
||||
total_turns: null,
|
||||
number_of_patients: null,
|
||||
today_turns: null,
|
||||
payments: null,
|
||||
todays_activities: [],
|
||||
list_of_doctors_appointments: [],
|
||||
chart_amount_income: [],
|
||||
};
|
||||
}
|
||||
|
||||
export function adaptRepresentationDashboard(dashboard) {
|
||||
const stats = dashboard?.data?.stats ?? dashboard?.stats ?? {};
|
||||
const daily = Array.isArray(stats.daily) ? stats.daily : [];
|
||||
|
||||
return {
|
||||
number_of_patients: stats.total_appointments ?? 0,
|
||||
today_turns: daily.length ? daily[daily.length - 1].appointments ?? 0 : 0,
|
||||
payments: stats.total_revenue_rials ?? 0,
|
||||
commission_rials: stats.commission_rials ?? 0,
|
||||
chart_amount_income: daily.map((d) => d.revenue ?? 0),
|
||||
list_of_doctors_appointments: daily.map((d) => ({
|
||||
name: "",
|
||||
expertise: "",
|
||||
image: DEFAULT_AVATAR,
|
||||
date: toJalali(d.date),
|
||||
hour: "",
|
||||
number_of_turns: d.appointments ?? 0,
|
||||
})),
|
||||
todays_activities: [],
|
||||
};
|
||||
}
|
||||
|
||||
export function buildPatientUser(profile, extras = {}) {
|
||||
// GET /user-profile is double-nested: { data: { data: {...} } } (after fetchReq → response.data)
|
||||
const data = profile?.data?.data ?? profile?.data ?? profile ?? {};
|
||||
@@ -81,17 +28,3 @@ export function buildPatientUser(profile, extras = {}) {
|
||||
messages: [],
|
||||
};
|
||||
}
|
||||
|
||||
export function adaptBankAccount(bankAccount) {
|
||||
if (!bankAccount) return [];
|
||||
return [
|
||||
{
|
||||
id: 1,
|
||||
card_number: bankAccount.account_number ?? "",
|
||||
shaba_number: bankAccount.iban ?? "",
|
||||
bank: bankAccount.bank_name ?? "",
|
||||
owner_name: bankAccount.owner_name ?? "",
|
||||
status: true,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user