recode and add editor config file
This commit is contained in:
@@ -1,128 +1,128 @@
|
||||
import { Avatar, Box, TextField } from "@mui/material";
|
||||
import { useState } from "react";
|
||||
import {Avatar, Box, TextField} from "@mui/material";
|
||||
import {useState} from "react";
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
|
||||
const AvatarUpload = ({ user, setFieldValue, valueAvatar, changeFlag }) => {
|
||||
const [selectedImage, setSelectedImage] = useState(user.expert_avatar);
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const AvatarUpload = ({user, setFieldValue, valueAvatar, changeFlag}) => {
|
||||
const [selectedImage, setSelectedImage] = useState(user.expert_avatar);
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
|
||||
const handleImageChange = (event) => {
|
||||
const newImage = event.target?.files?.[0];
|
||||
if (newImage) {
|
||||
setSelectedImage(URL.createObjectURL(newImage));
|
||||
setFieldValue(valueAvatar, newImage);
|
||||
setFieldValue(changeFlag, true);
|
||||
} else {
|
||||
setSelectedImage("");
|
||||
setFieldValue(valueAvatar, null);
|
||||
}
|
||||
};
|
||||
const handleImageChange = (event) => {
|
||||
const newImage = event.target?.files?.[0];
|
||||
if (newImage) {
|
||||
setSelectedImage(URL.createObjectURL(newImage));
|
||||
setFieldValue(valueAvatar, newImage);
|
||||
setFieldValue(changeFlag, true);
|
||||
} else {
|
||||
setSelectedImage("");
|
||||
setFieldValue(valueAvatar, null);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteImage = () => {
|
||||
setSelectedImage("");
|
||||
setFieldValue(valueAvatar, null);
|
||||
setFieldValue(changeFlag, true);
|
||||
};
|
||||
const handleDeleteImage = () => {
|
||||
setSelectedImage("");
|
||||
setFieldValue(valueAvatar, null);
|
||||
setFieldValue(changeFlag, true);
|
||||
};
|
||||
|
||||
const handleMouseEnter = () => {
|
||||
setIsHovered(true);
|
||||
};
|
||||
const handleMouseEnter = () => {
|
||||
setIsHovered(true);
|
||||
};
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
setIsHovered(false);
|
||||
};
|
||||
const handleMouseLeave = () => {
|
||||
setIsHovered(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "inline-block",
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
component="label"
|
||||
htmlFor="avatar-upload"
|
||||
sx={{
|
||||
display: "inline-block",
|
||||
width: "fit-content",
|
||||
height: "fit-content",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
return (
|
||||
<Box
|
||||
component="div"
|
||||
className={`avatar-container ${isHovered ? "hovered" : ""}`}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
sx={{
|
||||
position: "relative",
|
||||
width: 150,
|
||||
height: 150,
|
||||
borderRadius: "50%",
|
||||
overflow: "hidden",
|
||||
transition: "transform 0.3s ease-in-out",
|
||||
}}
|
||||
>
|
||||
<Avatar
|
||||
alt="User Avatar"
|
||||
src={selectedImage}
|
||||
sx={{
|
||||
width: 150,
|
||||
height: 150,
|
||||
cursor: "pointer",
|
||||
position: "relative",
|
||||
display: "inline-block",
|
||||
position: "relative",
|
||||
}}
|
||||
/>
|
||||
{isHovered && (
|
||||
>
|
||||
<Box
|
||||
component="div"
|
||||
className="avatar-overlay"
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
backgroundColor: "rgba(0, 0, 0, 0.6)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
transition: "transform 0.3s ease-in-out",
|
||||
transform: `scale(${isHovered ? 1 : 0})`,
|
||||
}}
|
||||
component="label"
|
||||
htmlFor="avatar-upload"
|
||||
sx={{
|
||||
display: "inline-block",
|
||||
width: "fit-content",
|
||||
height: "fit-content",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
{selectedImage ? (
|
||||
<DeleteIcon
|
||||
sx={{
|
||||
color: "#fff",
|
||||
width: 35,
|
||||
height: 35,
|
||||
}}
|
||||
onClick={handleDeleteImage}
|
||||
/>
|
||||
) : (
|
||||
<AddIcon
|
||||
sx={{
|
||||
color: "#fff",
|
||||
width: 35,
|
||||
height: 35,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Box
|
||||
component="div"
|
||||
className={`avatar-container ${isHovered ? "hovered" : ""}`}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
sx={{
|
||||
position: "relative",
|
||||
width: 150,
|
||||
height: 150,
|
||||
borderRadius: "50%",
|
||||
overflow: "hidden",
|
||||
transition: "transform 0.3s ease-in-out",
|
||||
}}
|
||||
>
|
||||
<Avatar
|
||||
alt="User Avatar"
|
||||
src={selectedImage}
|
||||
sx={{
|
||||
width: 150,
|
||||
height: 150,
|
||||
cursor: "pointer",
|
||||
position: "relative",
|
||||
}}
|
||||
/>
|
||||
{isHovered && (
|
||||
<Box
|
||||
component="div"
|
||||
className="avatar-overlay"
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
backgroundColor: "rgba(0, 0, 0, 0.6)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
transition: "transform 0.3s ease-in-out",
|
||||
transform: `scale(${isHovered ? 1 : 0})`,
|
||||
}}
|
||||
>
|
||||
{selectedImage ? (
|
||||
<DeleteIcon
|
||||
sx={{
|
||||
color: "#fff",
|
||||
width: 35,
|
||||
height: 35,
|
||||
}}
|
||||
onClick={handleDeleteImage}
|
||||
/>
|
||||
) : (
|
||||
<AddIcon
|
||||
sx={{
|
||||
color: "#fff",
|
||||
width: 35,
|
||||
height: 35,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
<TextField
|
||||
id="avatar-upload"
|
||||
type="file"
|
||||
accept="image/*"
|
||||
sx={{display: "none"}}
|
||||
onChange={handleImageChange}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
<TextField
|
||||
id="avatar-upload"
|
||||
type="file"
|
||||
accept="image/*"
|
||||
sx={{ display: "none" }}
|
||||
onChange={handleImageChange}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
export default AvatarUpload;
|
||||
|
||||
@@ -1,174 +1,174 @@
|
||||
import { ReloadDataTableContext } from "@/lib/app/contexts/ReloadDatatableContext";
|
||||
import {ReloadDataTableContext} from "@/lib/app/contexts/ReloadDatatableContext";
|
||||
import useLanguage from "@/lib/app/hooks/useLanguage";
|
||||
import { Typography } from "@mui/material";
|
||||
import {Typography} from "@mui/material";
|
||||
import axios from "axios";
|
||||
import MaterialReactTable from "material-react-table";
|
||||
import moment from "moment-jalaali";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useContext, useEffect, useMemo, useState } from "react";
|
||||
import {useTranslations} from "next-intl";
|
||||
import {useContext, useEffect, useMemo, useState} from "react";
|
||||
import useSWR from "swr";
|
||||
|
||||
const DataTable = (props) => {
|
||||
const { reloadDataTable, setReloadDataTable } = useContext(
|
||||
ReloadDataTableContext
|
||||
);
|
||||
|
||||
const fetcher = (...args) => {
|
||||
return axios
|
||||
.get(args, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${props.token}`,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
setRowCount(res.data.meta.totalRowCount);
|
||||
return res.data.data;
|
||||
});
|
||||
};
|
||||
const t = useTranslations();
|
||||
const { languageApp, languageList } = useLanguage();
|
||||
const [columnFilters, setColumnFilters] = useState([]);
|
||||
const [columnFilterFns, setColumnFilterFns] = useState(() => {
|
||||
let output = {};
|
||||
const list = props.columns.map((item) =>
|
||||
item.enableColumnFilter ? { [item.id]: item.filterFn } : { [item.id]: "" }
|
||||
const {reloadDataTable, setReloadDataTable} = useContext(
|
||||
ReloadDataTableContext
|
||||
);
|
||||
for (var key in list) {
|
||||
var nestedObj = list[key];
|
||||
for (var nestedKey in nestedObj) {
|
||||
output[nestedKey] = nestedObj[nestedKey];
|
||||
}
|
||||
}
|
||||
return output;
|
||||
});
|
||||
const [sorting, setSorting] = useState([]);
|
||||
const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 });
|
||||
const [rowCount, setRowCount] = useState(0);
|
||||
const [updateTime, setupdateTime] = useState(
|
||||
moment().format("HH:mm | jYYYY/jM/jD")
|
||||
);
|
||||
|
||||
const tableLocalization = useMemo(
|
||||
() =>
|
||||
languageList.find((item) => item.key == languageApp).tableLocalization,
|
||||
[languageApp, languageList]
|
||||
);
|
||||
|
||||
const fetchUrl = useMemo(() => {
|
||||
const url = new URL(props.tableUrl /* send your api */);
|
||||
url.searchParams.set(
|
||||
"start",
|
||||
`${pagination.pageIndex * pagination.pageSize}`
|
||||
);
|
||||
const filters = columnFilters.map((filter) => {
|
||||
let datatype;
|
||||
for (const i in props.columns) {
|
||||
if (props.columns[i].id == filter.id) {
|
||||
datatype = props.columns[i].datatype;
|
||||
const fetcher = (...args) => {
|
||||
return axios
|
||||
.get(args, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${props.token}`,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
setRowCount(res.data.meta.totalRowCount);
|
||||
return res.data.data;
|
||||
});
|
||||
};
|
||||
const t = useTranslations();
|
||||
const {languageApp, languageList} = useLanguage();
|
||||
const [columnFilters, setColumnFilters] = useState([]);
|
||||
const [columnFilterFns, setColumnFilterFns] = useState(() => {
|
||||
let output = {};
|
||||
const list = props.columns.map((item) =>
|
||||
item.enableColumnFilter ? {[item.id]: item.filterFn} : {[item.id]: ""}
|
||||
);
|
||||
for (var key in list) {
|
||||
var nestedObj = list[key];
|
||||
for (var nestedKey in nestedObj) {
|
||||
output[nestedKey] = nestedObj[nestedKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
...filter,
|
||||
fn: columnFilterFns[filter.id],
|
||||
datatype: datatype,
|
||||
};
|
||||
return output;
|
||||
});
|
||||
url.searchParams.set("size", pagination.pageSize);
|
||||
url.searchParams.set("filters", JSON.stringify(filters ?? []));
|
||||
url.searchParams.set("sorting", JSON.stringify(sorting ?? []));
|
||||
return url;
|
||||
}, [
|
||||
props.tableUrl,
|
||||
columnFilters,
|
||||
columnFilterFns,
|
||||
pagination,
|
||||
sorting,
|
||||
props.columns,
|
||||
]);
|
||||
const { data, isLoading, isValidating, mutate } = useSWR(fetchUrl, fetcher, {
|
||||
revalidateOnFocus: false,
|
||||
});
|
||||
const [sorting, setSorting] = useState([]);
|
||||
const [pagination, setPagination] = useState({pageIndex: 0, pageSize: 10});
|
||||
const [rowCount, setRowCount] = useState(0);
|
||||
const [updateTime, setupdateTime] = useState(
|
||||
moment().format("HH:mm | jYYYY/jM/jD")
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (reloadDataTable) {
|
||||
mutate(fetchUrl).then(() => {
|
||||
setReloadDataTable(false); // Set reloadDataTable to false after mutation is complete
|
||||
});
|
||||
}
|
||||
}, [reloadDataTable, setReloadDataTable]);
|
||||
const tableLocalization = useMemo(
|
||||
() =>
|
||||
languageList.find((item) => item.key == languageApp).tableLocalization,
|
||||
[languageApp, languageList]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setupdateTime(moment().format("HH:mm | jYYYY/jM/jD"));
|
||||
}, [isValidating, languageApp]);
|
||||
|
||||
return (
|
||||
<MaterialReactTable
|
||||
localization={tableLocalization}
|
||||
columns={props.columns} /* columns you send */
|
||||
data={data ?? []}
|
||||
manualFiltering
|
||||
manualPagination
|
||||
manualSorting
|
||||
enableRowSelection={props.selectableRow} /* send condition */
|
||||
enablePinning={props.enablePinning} /* send condition */
|
||||
enableColumnFilters={props.enableColumnFilters} /* send condition */
|
||||
enableDensityToggle={props.enableDensityToggle} /* send condition */
|
||||
enableHiding={props.enableHiding} /* send condition */
|
||||
enableFullScreenToggle={props.enableFullScreenToggle} /* send condition */
|
||||
enableColumnResizing={props.enableColumnResizing}
|
||||
muiTableHeadCellProps={{
|
||||
sx: {
|
||||
color: "primary.main",
|
||||
"& .Mui-TableHeadCell-Content": { justifyContent: "space-between" },
|
||||
},
|
||||
}}
|
||||
enableColumnFilterModes
|
||||
muiTablePaperProps={{ elevation: 0 }}
|
||||
rowCount={rowCount}
|
||||
onColumnFilterFnsChange={setColumnFilterFns}
|
||||
onColumnFiltersChange={setColumnFilters}
|
||||
onPaginationChange={setPagination}
|
||||
onSortingChange={setSorting}
|
||||
positionToolbarAlertBanner="bottom"
|
||||
renderTopToolbarCustomActions={({ table }) => (
|
||||
<>
|
||||
{props.enableCustomToolbar /* send condition */
|
||||
? props.CustomToolbar /* send component */
|
||||
: ""}
|
||||
</>
|
||||
)}
|
||||
renderBottomToolbarCustomActions={({ table }) => (
|
||||
<>
|
||||
{props.enableLastUpdate /* send condition */ ? (
|
||||
<Typography
|
||||
sx={{
|
||||
color: "primary.main",
|
||||
alignSelf: "center",
|
||||
whiteSpace: "nowrap",
|
||||
maxWidth: { xs: 100, sm: "100%" },
|
||||
overflowX: "scroll",
|
||||
}}
|
||||
variant="caption"
|
||||
>
|
||||
{t("last_updated_at")}: {updateTime}
|
||||
</Typography>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
state={{
|
||||
isLoading,
|
||||
const fetchUrl = useMemo(() => {
|
||||
const url = new URL(props.tableUrl /* send your api */);
|
||||
url.searchParams.set(
|
||||
"start",
|
||||
`${pagination.pageIndex * pagination.pageSize}`
|
||||
);
|
||||
const filters = columnFilters.map((filter) => {
|
||||
let datatype;
|
||||
for (const i in props.columns) {
|
||||
if (props.columns[i].id == filter.id) {
|
||||
datatype = props.columns[i].datatype;
|
||||
}
|
||||
}
|
||||
return {
|
||||
...filter,
|
||||
fn: columnFilterFns[filter.id],
|
||||
datatype: datatype,
|
||||
};
|
||||
});
|
||||
url.searchParams.set("size", pagination.pageSize);
|
||||
url.searchParams.set("filters", JSON.stringify(filters ?? []));
|
||||
url.searchParams.set("sorting", JSON.stringify(sorting ?? []));
|
||||
return url;
|
||||
}, [
|
||||
props.tableUrl,
|
||||
columnFilters,
|
||||
columnFilterFns,
|
||||
pagination,
|
||||
sorting,
|
||||
}}
|
||||
positionActionsColumn={"last"}
|
||||
enableRowActions={props.enableRowActions}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
props.columns,
|
||||
]);
|
||||
const {data, isLoading, isValidating, mutate} = useSWR(fetchUrl, fetcher, {
|
||||
revalidateOnFocus: false,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (reloadDataTable) {
|
||||
mutate(fetchUrl).then(() => {
|
||||
setReloadDataTable(false); // Set reloadDataTable to false after mutation is complete
|
||||
});
|
||||
}
|
||||
}, [reloadDataTable, setReloadDataTable]);
|
||||
|
||||
useEffect(() => {
|
||||
setupdateTime(moment().format("HH:mm | jYYYY/jM/jD"));
|
||||
}, [isValidating, languageApp]);
|
||||
|
||||
return (
|
||||
<MaterialReactTable
|
||||
localization={tableLocalization}
|
||||
columns={props.columns} /* columns you send */
|
||||
data={data ?? []}
|
||||
manualFiltering
|
||||
manualPagination
|
||||
manualSorting
|
||||
enableRowSelection={props.selectableRow} /* send condition */
|
||||
enablePinning={props.enablePinning} /* send condition */
|
||||
enableColumnFilters={props.enableColumnFilters} /* send condition */
|
||||
enableDensityToggle={props.enableDensityToggle} /* send condition */
|
||||
enableHiding={props.enableHiding} /* send condition */
|
||||
enableFullScreenToggle={props.enableFullScreenToggle} /* send condition */
|
||||
enableColumnResizing={props.enableColumnResizing}
|
||||
muiTableHeadCellProps={{
|
||||
sx: {
|
||||
color: "primary.main",
|
||||
"& .Mui-TableHeadCell-Content": {justifyContent: "space-between"},
|
||||
},
|
||||
}}
|
||||
enableColumnFilterModes
|
||||
muiTablePaperProps={{elevation: 0}}
|
||||
rowCount={rowCount}
|
||||
onColumnFilterFnsChange={setColumnFilterFns}
|
||||
onColumnFiltersChange={setColumnFilters}
|
||||
onPaginationChange={setPagination}
|
||||
onSortingChange={setSorting}
|
||||
positionToolbarAlertBanner="bottom"
|
||||
renderTopToolbarCustomActions={({table}) => (
|
||||
<>
|
||||
{props.enableCustomToolbar /* send condition */
|
||||
? props.CustomToolbar /* send component */
|
||||
: ""}
|
||||
</>
|
||||
)}
|
||||
renderBottomToolbarCustomActions={({table}) => (
|
||||
<>
|
||||
{props.enableLastUpdate /* send condition */ ? (
|
||||
<Typography
|
||||
sx={{
|
||||
color: "primary.main",
|
||||
alignSelf: "center",
|
||||
whiteSpace: "nowrap",
|
||||
maxWidth: {xs: 100, sm: "100%"},
|
||||
overflowX: "scroll",
|
||||
}}
|
||||
variant="caption"
|
||||
>
|
||||
{t("last_updated_at")}: {updateTime}
|
||||
</Typography>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
state={{
|
||||
isLoading,
|
||||
columnFilters,
|
||||
columnFilterFns,
|
||||
pagination,
|
||||
sorting,
|
||||
}}
|
||||
positionActionsColumn={"last"}
|
||||
enableRowActions={props.enableRowActions}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default DataTable;
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { DataTableProvider } from "@/lib/app/contexts/DatatableContext";
|
||||
import {DataTableProvider} from "@/lib/app/contexts/DatatableContext";
|
||||
import DataTable from "./Datatable";
|
||||
import { ReloadDataTableProvider } from "@/lib/app/contexts/ReloadDatatableContext";
|
||||
import {ReloadDataTableProvider} from "@/lib/app/contexts/ReloadDatatableContext";
|
||||
|
||||
function DataTableStructure(props) {
|
||||
return (
|
||||
<ReloadDataTableProvider>
|
||||
<DataTableProvider>
|
||||
<DataTable {...props} token={localStorage.getItem("_token")} />
|
||||
</DataTableProvider>
|
||||
</ReloadDataTableProvider>
|
||||
);
|
||||
return (
|
||||
<ReloadDataTableProvider>
|
||||
<DataTableProvider>
|
||||
<DataTable {...props} token={localStorage.getItem("_token")}/>
|
||||
</DataTableProvider>
|
||||
</ReloadDataTableProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default DataTableStructure;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Typography } from "@mui/material";
|
||||
import {Typography} from "@mui/material";
|
||||
|
||||
const FormErrorMessage = (props) => {
|
||||
return (
|
||||
<Typography variant="body2" color="error">
|
||||
{props.children}
|
||||
</Typography>
|
||||
);
|
||||
return (
|
||||
<Typography variant="body2" color="error">
|
||||
{props.children}
|
||||
</Typography>
|
||||
);
|
||||
};
|
||||
|
||||
export default FormErrorMessage;
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import ImageResize from "image-resize";
|
||||
|
||||
const ImageResizer = async (image) => {
|
||||
const imageResize = new ImageResize({
|
||||
quality: 1,
|
||||
format: "jpg",
|
||||
outputType: "base64",
|
||||
width: 400,
|
||||
});
|
||||
const imageResize = new ImageResize({
|
||||
quality: 1,
|
||||
format: "jpg",
|
||||
outputType: "base64",
|
||||
width: 400,
|
||||
});
|
||||
|
||||
const get = await imageResize.get(image);
|
||||
const resize = await imageResize.resize(get).then();
|
||||
const output = await imageResize.output(resize).then();
|
||||
const get = await imageResize.get(image);
|
||||
const resize = await imageResize.resize(get).then();
|
||||
const output = await imageResize.output(resize).then();
|
||||
|
||||
const avatar = await (await import("image-to-file-converter"))
|
||||
.base64ToFile(output)
|
||||
.then();
|
||||
const avatar = await (await import("image-to-file-converter"))
|
||||
.base64ToFile(output)
|
||||
.then();
|
||||
|
||||
return avatar;
|
||||
return avatar;
|
||||
};
|
||||
|
||||
export default ImageResizer;
|
||||
|
||||
@@ -1,116 +1,116 @@
|
||||
import MuiLink from "@mui/material/Link";
|
||||
import { styled } from "@mui/material/styles";
|
||||
import {styled} from "@mui/material/styles";
|
||||
import clsx from "clsx";
|
||||
import NextLink from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import {useRouter} from "next/router";
|
||||
import * as React from "react";
|
||||
|
||||
// Add support for the sx prop for consistency with the other branches.
|
||||
const Anchor = styled("a")({});
|
||||
|
||||
export const NextLinkComposed = React.forwardRef(function NextLinkComposed(
|
||||
props,
|
||||
ref
|
||||
props,
|
||||
ref
|
||||
) {
|
||||
const {
|
||||
to,
|
||||
linkAs,
|
||||
replace,
|
||||
scroll,
|
||||
shallow,
|
||||
prefetch,
|
||||
legacyBehavior = true,
|
||||
locale,
|
||||
...other
|
||||
} = props;
|
||||
const {
|
||||
to,
|
||||
linkAs,
|
||||
replace,
|
||||
scroll,
|
||||
shallow,
|
||||
prefetch,
|
||||
legacyBehavior = true,
|
||||
locale,
|
||||
...other
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<NextLink
|
||||
href={to}
|
||||
prefetch={prefetch}
|
||||
as={linkAs}
|
||||
replace={replace}
|
||||
scroll={scroll}
|
||||
shallow={shallow}
|
||||
passHref
|
||||
locale={locale}
|
||||
legacyBehavior={legacyBehavior}
|
||||
>
|
||||
<Anchor ref={ref} {...other} />
|
||||
</NextLink>
|
||||
);
|
||||
return (
|
||||
<NextLink
|
||||
href={to}
|
||||
prefetch={prefetch}
|
||||
as={linkAs}
|
||||
replace={replace}
|
||||
scroll={scroll}
|
||||
shallow={shallow}
|
||||
passHref
|
||||
locale={locale}
|
||||
legacyBehavior={legacyBehavior}
|
||||
>
|
||||
<Anchor ref={ref} {...other} />
|
||||
</NextLink>
|
||||
);
|
||||
});
|
||||
|
||||
// A styled version of the Next.js Link component:
|
||||
// https://nextjs.org/docs/api-reference/next/link
|
||||
const LinkRouting = React.forwardRef(function Link(props, ref) {
|
||||
const {
|
||||
activeClassName = "active",
|
||||
as,
|
||||
className: classNameProps,
|
||||
href,
|
||||
legacyBehavior,
|
||||
linkAs: linkAsProp,
|
||||
locale,
|
||||
noLinkStyle,
|
||||
prefetch,
|
||||
replace,
|
||||
role, // Link don't have roles.
|
||||
scroll,
|
||||
shallow,
|
||||
...other
|
||||
} = props;
|
||||
const {
|
||||
activeClassName = "active",
|
||||
as,
|
||||
className: classNameProps,
|
||||
href,
|
||||
legacyBehavior,
|
||||
linkAs: linkAsProp,
|
||||
locale,
|
||||
noLinkStyle,
|
||||
prefetch,
|
||||
replace,
|
||||
role, // Link don't have roles.
|
||||
scroll,
|
||||
shallow,
|
||||
...other
|
||||
} = props;
|
||||
|
||||
const router = useRouter();
|
||||
const pathname = typeof href === "string" ? href : href.pathname;
|
||||
const className = clsx(classNameProps, {
|
||||
[activeClassName]: router.pathname === pathname && activeClassName,
|
||||
});
|
||||
const router = useRouter();
|
||||
const pathname = typeof href === "string" ? href : href.pathname;
|
||||
const className = clsx(classNameProps, {
|
||||
[activeClassName]: router.pathname === pathname && activeClassName,
|
||||
});
|
||||
|
||||
const isExternal =
|
||||
typeof href === "string" &&
|
||||
(href.indexOf("http") === 0 || href.indexOf("mailto:") === 0);
|
||||
const isExternal =
|
||||
typeof href === "string" &&
|
||||
(href.indexOf("http") === 0 || href.indexOf("mailto:") === 0);
|
||||
|
||||
if (isExternal) {
|
||||
if (noLinkStyle) {
|
||||
return <Anchor className={className} href={href} ref={ref} {...other} />;
|
||||
if (isExternal) {
|
||||
if (noLinkStyle) {
|
||||
return <Anchor className={className} href={href} ref={ref} {...other} />;
|
||||
}
|
||||
|
||||
return <MuiLink className={className} href={href} ref={ref} {...other} />;
|
||||
}
|
||||
|
||||
return <MuiLink className={className} href={href} ref={ref} {...other} />;
|
||||
}
|
||||
const linkAs = linkAsProp || as;
|
||||
const nextjsProps = {
|
||||
to: href,
|
||||
linkAs,
|
||||
replace,
|
||||
scroll,
|
||||
shallow,
|
||||
prefetch,
|
||||
legacyBehavior,
|
||||
locale,
|
||||
};
|
||||
|
||||
const linkAs = linkAsProp || as;
|
||||
const nextjsProps = {
|
||||
to: href,
|
||||
linkAs,
|
||||
replace,
|
||||
scroll,
|
||||
shallow,
|
||||
prefetch,
|
||||
legacyBehavior,
|
||||
locale,
|
||||
};
|
||||
if (noLinkStyle) {
|
||||
return (
|
||||
<NextLinkComposed
|
||||
className={className}
|
||||
ref={ref}
|
||||
{...nextjsProps}
|
||||
{...other}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (noLinkStyle) {
|
||||
return (
|
||||
<NextLinkComposed
|
||||
className={className}
|
||||
ref={ref}
|
||||
{...nextjsProps}
|
||||
{...other}
|
||||
/>
|
||||
<MuiLink
|
||||
component={NextLinkComposed}
|
||||
className={className}
|
||||
ref={ref}
|
||||
{...nextjsProps}
|
||||
{...other}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<MuiLink
|
||||
component={NextLinkComposed}
|
||||
className={className}
|
||||
ref={ref}
|
||||
{...nextjsProps}
|
||||
{...other}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
export default LinkRouting;
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
import { Backdrop, Fade, styled } from "@mui/material";
|
||||
import {Backdrop, Fade, styled} from "@mui/material";
|
||||
import StyledImage from "./StyledImage";
|
||||
|
||||
const LoadingImage = styled(StyledImage)({
|
||||
"@keyframes load": {
|
||||
"0%": {
|
||||
// opacity: 0,
|
||||
transform: "scale(1)",
|
||||
"@keyframes load": {
|
||||
"0%": {
|
||||
// opacity: 0,
|
||||
transform: "scale(1)",
|
||||
},
|
||||
"50%": {
|
||||
// opacity: 1,
|
||||
transform: "scale(2)",
|
||||
},
|
||||
"100%": {
|
||||
// opacity: 0,
|
||||
transform: "scale(1)",
|
||||
},
|
||||
},
|
||||
"50%": {
|
||||
// opacity: 1,
|
||||
transform: "scale(2)",
|
||||
},
|
||||
"100%": {
|
||||
// opacity: 0,
|
||||
transform: "scale(1)",
|
||||
},
|
||||
},
|
||||
animation: "load 2s infinite",
|
||||
animation: "load 2s infinite",
|
||||
});
|
||||
|
||||
const LoadingHardPage = ({ children, loading }) => {
|
||||
return (
|
||||
<>
|
||||
<Backdrop
|
||||
sx={{ bgcolor: "#fff", zIndex: (theme) => theme.zIndex.drawer + 1 }}
|
||||
open={loading}
|
||||
>
|
||||
<Fade in={true}>
|
||||
<LoadingImage
|
||||
src={"/images/loading_logo.svg"}
|
||||
alt="loading marhaba"
|
||||
priority
|
||||
width={100}
|
||||
height={100}
|
||||
/>
|
||||
</Fade>
|
||||
</Backdrop>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
const LoadingHardPage = ({children, loading}) => {
|
||||
return (
|
||||
<>
|
||||
<Backdrop
|
||||
sx={{bgcolor: "#fff", zIndex: (theme) => theme.zIndex.drawer + 1}}
|
||||
open={loading}
|
||||
>
|
||||
<Fade in={true}>
|
||||
<LoadingImage
|
||||
src={"/images/loading_logo.svg"}
|
||||
alt="loading marhaba"
|
||||
priority
|
||||
width={100}
|
||||
height={100}
|
||||
/>
|
||||
</Fade>
|
||||
</Backdrop>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoadingHardPage;
|
||||
|
||||
@@ -2,21 +2,21 @@ import CenterLayout from "@/layouts/CenterLayout";
|
||||
import FullPageLayout from "@/layouts/FullPageLayout";
|
||||
import StyledImage from "./StyledImage";
|
||||
|
||||
const Message = ({ text, actions }) => {
|
||||
return (
|
||||
<FullPageLayout sx={{ p: 1 }}>
|
||||
<CenterLayout spacing={3}>
|
||||
<StyledImage
|
||||
src={"/images/loading_logo.svg"}
|
||||
alt="loading loan facilities"
|
||||
width={100}
|
||||
height={100}
|
||||
/>
|
||||
{text}
|
||||
{actions}
|
||||
</CenterLayout>
|
||||
</FullPageLayout>
|
||||
);
|
||||
const Message = ({text, actions}) => {
|
||||
return (
|
||||
<FullPageLayout sx={{p: 1}}>
|
||||
<CenterLayout spacing={3}>
|
||||
<StyledImage
|
||||
src={"/images/loading_logo.svg"}
|
||||
alt="loading loan facilities"
|
||||
width={100}
|
||||
height={100}
|
||||
/>
|
||||
{text}
|
||||
{actions}
|
||||
</CenterLayout>
|
||||
</FullPageLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default Message;
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
import { LocalizationProvider, DatePicker } from "@mui/x-date-pickers";
|
||||
import { AdapterDateFnsJalali } from "@mui/x-date-pickers/AdapterDateFnsJalali";
|
||||
import {DatePicker, LocalizationProvider} from "@mui/x-date-pickers";
|
||||
import {AdapterDateFnsJalali} from "@mui/x-date-pickers/AdapterDateFnsJalali";
|
||||
import moment from "jalali-moment";
|
||||
import { useTranslations } from "next-intl";
|
||||
import {useTranslations} from "next-intl";
|
||||
|
||||
export default function MuiDatePicker({
|
||||
setFieldValue,
|
||||
selectType,
|
||||
error,
|
||||
helperText,
|
||||
}) {
|
||||
const t = useTranslations();
|
||||
setFieldValue,
|
||||
selectType,
|
||||
error,
|
||||
helperText,
|
||||
}) {
|
||||
const t = useTranslations();
|
||||
|
||||
const handleDateChange = (date) => {
|
||||
const selectedDate = moment(date).locale("fa"); // should add .format() at the end to format the data
|
||||
setFieldValue(selectType, selectedDate);
|
||||
};
|
||||
const handleDateChange = (date) => {
|
||||
const selectedDate = moment(date).locale("fa"); // should add .format() at the end to format the data
|
||||
setFieldValue(selectType, selectedDate);
|
||||
};
|
||||
|
||||
return (
|
||||
<LocalizationProvider dateAdapter={AdapterDateFnsJalali}>
|
||||
<DatePicker
|
||||
sx={{ width: "100%" }}
|
||||
label={t("MuiDatePicker.date_picker_birthday")}
|
||||
slotProps={{
|
||||
textField: {
|
||||
size: "small",
|
||||
helperText: helperText ? `${helperText}` : "YYYY-MM-DD",
|
||||
error: error ? true : false,
|
||||
},
|
||||
}}
|
||||
onChange={handleDateChange}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
);
|
||||
return (
|
||||
<LocalizationProvider dateAdapter={AdapterDateFnsJalali}>
|
||||
<DatePicker
|
||||
sx={{width: "100%"}}
|
||||
label={t("MuiDatePicker.date_picker_birthday")}
|
||||
slotProps={{
|
||||
textField: {
|
||||
size: "small",
|
||||
helperText: helperText ? `${helperText}` : "YYYY-MM-DD",
|
||||
error: error ? true : false,
|
||||
},
|
||||
}}
|
||||
onChange={handleDateChange}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
import { useState } from "react";
|
||||
import { IconButton, InputAdornment, TextField } from "@mui/material";
|
||||
import { Visibility, VisibilityOff } from "@mui/icons-material";
|
||||
import { Field } from "formik";
|
||||
import {useState} from "react";
|
||||
import {IconButton, InputAdornment, TextField} from "@mui/material";
|
||||
import {Visibility, VisibilityOff} from "@mui/icons-material";
|
||||
import {Field} from "formik";
|
||||
|
||||
const PasswordField = (props) => {
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
|
||||
const handleClickShowPassword = () => {
|
||||
setShowPassword(!showPassword);
|
||||
};
|
||||
const handleClickShowPassword = () => {
|
||||
setShowPassword(!showPassword);
|
||||
};
|
||||
|
||||
return (
|
||||
<Field
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
as={TextField}
|
||||
{...props}
|
||||
type={showPassword ? "text" : "password"}
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
<IconButton onClick={handleClickShowPassword}>
|
||||
{showPassword ? <Visibility /> : <VisibilityOff />}
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<Field
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
as={TextField}
|
||||
{...props}
|
||||
type={showPassword ? "text" : "password"}
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
<IconButton onClick={handleClickShowPassword}>
|
||||
{showPassword ? <Visibility/> : <VisibilityOff/>}
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default PasswordField;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { styled } from "@mui/material";
|
||||
import { Form } from "formik";
|
||||
import {styled} from "@mui/material";
|
||||
import {Form} from "formik";
|
||||
|
||||
const StyledForm = styled(Form)``;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { styled } from "@mui/material";
|
||||
import {styled} from "@mui/material";
|
||||
import Image from "next/image";
|
||||
|
||||
const StyledImage = styled(Image)``;
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { useTranslations } from "next-intl";
|
||||
import {useTranslations} from "next-intl";
|
||||
import Head from "next/head";
|
||||
|
||||
const TitlePage = ({ text }) => {
|
||||
const t = useTranslations();
|
||||
return (
|
||||
<Head>
|
||||
<title>
|
||||
{text ? `${t("app_short_name")} | ${t(text)}` : t("app_short_name")}
|
||||
</title>
|
||||
</Head>
|
||||
);
|
||||
const TitlePage = ({text}) => {
|
||||
const t = useTranslations();
|
||||
return (
|
||||
<Head>
|
||||
<title>
|
||||
{text ? `${t("app_short_name")} | ${t(text)}` : t("app_short_name")}
|
||||
</title>
|
||||
</Head>
|
||||
);
|
||||
};
|
||||
|
||||
export default TitlePage;
|
||||
|
||||
@@ -1,176 +1,175 @@
|
||||
import { Box, Button, Paper, Typography } from "@mui/material";
|
||||
import { useTranslations } from "next-intl";
|
||||
import Image from "next/image";
|
||||
import {Box, Button, Paper, Typography} from "@mui/material";
|
||||
import {useTranslations} from "next-intl";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import DeleteForeverIcon from "@mui/icons-material/DeleteForever";
|
||||
import { useRef } from "react";
|
||||
import {useRef} from "react";
|
||||
|
||||
const UploadSystem = ({
|
||||
selectedImage,
|
||||
setselectedImage,
|
||||
handleUploadChange,
|
||||
fieldname,
|
||||
setFieldValue,
|
||||
imageAlt,
|
||||
imageSize,
|
||||
fileType,
|
||||
fileName,
|
||||
setShowAddIcon,
|
||||
showAddIcon,
|
||||
}) => {
|
||||
const t = useTranslations();
|
||||
const fileInputRef = useRef(null);
|
||||
selectedImage,
|
||||
setselectedImage,
|
||||
handleUploadChange,
|
||||
fieldname,
|
||||
setFieldValue,
|
||||
imageAlt,
|
||||
imageSize,
|
||||
fileType,
|
||||
fileName,
|
||||
setShowAddIcon,
|
||||
showAddIcon,
|
||||
}) => {
|
||||
const t = useTranslations();
|
||||
const fileInputRef = useRef(null);
|
||||
|
||||
const handleClick = () => {
|
||||
fileInputRef.current.click();
|
||||
};
|
||||
const handleClick = () => {
|
||||
fileInputRef.current.click();
|
||||
};
|
||||
|
||||
const handleDeleteImage = () => {
|
||||
setselectedImage(null);
|
||||
setFieldValue(fieldname, null);
|
||||
setShowAddIcon(true);
|
||||
if (fileInputRef.current) {
|
||||
fileInputRef.current.value = "";
|
||||
}
|
||||
};
|
||||
const handleDeleteImage = () => {
|
||||
setselectedImage(null);
|
||||
setFieldValue(fieldname, null);
|
||||
setShowAddIcon(true);
|
||||
if (fileInputRef.current) {
|
||||
fileInputRef.current.value = "";
|
||||
}
|
||||
};
|
||||
|
||||
const isDocumentFormat = (fileType) => {
|
||||
const documentFormats = [
|
||||
"application/pdf",
|
||||
"application/msword",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
"application/vnd.ms-excel",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
];
|
||||
return documentFormats.includes(fileType);
|
||||
};
|
||||
const isDocumentFormat = (fileType) => {
|
||||
const documentFormats = [
|
||||
"application/pdf",
|
||||
"application/msword",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
"application/vnd.ms-excel",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
];
|
||||
return documentFormats.includes(fileType);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ width: "100%", my: 1 }}>
|
||||
{showAddIcon ? (
|
||||
// Show the add icon and "Upload File" text when no image is selected
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
border: "1px solid #b3b3b3",
|
||||
borderRadius: "10px",
|
||||
cursor: "pointer",
|
||||
padding: "5px",
|
||||
return (
|
||||
<Box sx={{width: "100%", my: 1}}>
|
||||
{showAddIcon ? (
|
||||
// Show the add icon and "Upload File" text when no image is selected
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
border: "1px solid #b3b3b3",
|
||||
borderRadius: "10px",
|
||||
cursor: "pointer",
|
||||
padding: "5px",
|
||||
|
||||
height: imageSize[1],
|
||||
}}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<AddIcon sx={{ fontSize: "2rem", color: "#a19d9d" }} />
|
||||
<Typography
|
||||
variant="subtitle2"
|
||||
sx={{
|
||||
fontWeight: 600,
|
||||
fontSize: "1rem",
|
||||
color: "#a19d9d",
|
||||
mt: 1,
|
||||
}}
|
||||
textAlign="center"
|
||||
>
|
||||
{t("UploadSystem.upload_file")}
|
||||
</Typography>
|
||||
</Box>
|
||||
</>
|
||||
) : (
|
||||
// Show the uploaded content along with the delete button when an image or document is selected
|
||||
<>
|
||||
{fileType && fileType.startsWith("image/") ? (
|
||||
<Box
|
||||
width="100%"
|
||||
height={imageSize[1]}
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
cursor: "pointer",
|
||||
objectFit: "contain",
|
||||
border: "1px solid #b3b3b3",
|
||||
borderTopRightRadius: "10px",
|
||||
borderTopLeftRadius: "10px",
|
||||
borderBottom: "unset",
|
||||
padding: "5px",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundSize: "contain",
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundPosition: "center",
|
||||
backgroundImage: `url(${selectedImage})`,
|
||||
}}
|
||||
></Paper>
|
||||
</Box>
|
||||
) : (
|
||||
fileType &&
|
||||
isDocumentFormat(fileType) && (
|
||||
<Box
|
||||
sx={{
|
||||
height: imageSize[1],
|
||||
display: "flex",
|
||||
border: "1px solid #b3b3b3",
|
||||
borderTopRightRadius: "10px",
|
||||
borderTopLeftRadius: "10px",
|
||||
borderBottom: "unset",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<Typography
|
||||
margin={2}
|
||||
sx={{
|
||||
fontWeight: 600,
|
||||
fontSize: "1rem",
|
||||
color: "#a19d9d",
|
||||
}}
|
||||
textAlign="center"
|
||||
>
|
||||
{fileName}
|
||||
</Typography>
|
||||
</Box>
|
||||
)
|
||||
)}
|
||||
<Button
|
||||
sx={{
|
||||
width: "100%",
|
||||
}}
|
||||
color="error"
|
||||
endIcon={<DeleteForeverIcon />}
|
||||
variant="contained"
|
||||
onClick={handleDeleteImage}
|
||||
>
|
||||
{t("UploadSystem.delete")}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*, .pdf, .doc, .docx, .xls, .xlsx"
|
||||
style={{ display: "none" }}
|
||||
onChange={handleUploadChange}
|
||||
ref={fileInputRef}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
height: imageSize[1],
|
||||
}}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<AddIcon sx={{fontSize: "2rem", color: "#a19d9d"}}/>
|
||||
<Typography
|
||||
variant="subtitle2"
|
||||
sx={{
|
||||
fontWeight: 600,
|
||||
fontSize: "1rem",
|
||||
color: "#a19d9d",
|
||||
mt: 1,
|
||||
}}
|
||||
textAlign="center"
|
||||
>
|
||||
{t("UploadSystem.upload_file")}
|
||||
</Typography>
|
||||
</Box>
|
||||
</>
|
||||
) : (
|
||||
// Show the uploaded content along with the delete button when an image or document is selected
|
||||
<>
|
||||
{fileType && fileType.startsWith("image/") ? (
|
||||
<Box
|
||||
width="100%"
|
||||
height={imageSize[1]}
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
cursor: "pointer",
|
||||
objectFit: "contain",
|
||||
border: "1px solid #b3b3b3",
|
||||
borderTopRightRadius: "10px",
|
||||
borderTopLeftRadius: "10px",
|
||||
borderBottom: "unset",
|
||||
padding: "5px",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundSize: "contain",
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundPosition: "center",
|
||||
backgroundImage: `url(${selectedImage})`,
|
||||
}}
|
||||
></Paper>
|
||||
</Box>
|
||||
) : (
|
||||
fileType &&
|
||||
isDocumentFormat(fileType) && (
|
||||
<Box
|
||||
sx={{
|
||||
height: imageSize[1],
|
||||
display: "flex",
|
||||
border: "1px solid #b3b3b3",
|
||||
borderTopRightRadius: "10px",
|
||||
borderTopLeftRadius: "10px",
|
||||
borderBottom: "unset",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<Typography
|
||||
margin={2}
|
||||
sx={{
|
||||
fontWeight: 600,
|
||||
fontSize: "1rem",
|
||||
color: "#a19d9d",
|
||||
}}
|
||||
textAlign="center"
|
||||
>
|
||||
{fileName}
|
||||
</Typography>
|
||||
</Box>
|
||||
)
|
||||
)}
|
||||
<Button
|
||||
sx={{
|
||||
width: "100%",
|
||||
}}
|
||||
color="error"
|
||||
endIcon={<DeleteForeverIcon/>}
|
||||
variant="contained"
|
||||
onClick={handleDeleteImage}
|
||||
>
|
||||
{t("UploadSystem.delete")}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*, .pdf, .doc, .docx, .xls, .xlsx"
|
||||
style={{display: "none"}}
|
||||
onChange={handleUploadChange}
|
||||
ref={fileInputRef}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default UploadSystem;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { NoSsr } from "@mui/material";
|
||||
import {NoSsr} from "@mui/material";
|
||||
|
||||
const NoSsrHandler = ({ isBot, children }) => {
|
||||
if (isBot) return children;
|
||||
return <NoSsr>{children}</NoSsr>;
|
||||
const NoSsrHandler = ({isBot, children}) => {
|
||||
if (isBot) return children;
|
||||
return <NoSsr>{children}</NoSsr>;
|
||||
};
|
||||
|
||||
export default NoSsrHandler;
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
import DangerousIcon from "@mui/icons-material/Dangerous";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { toast } from "react-toastify";
|
||||
import {Box, Typography} from "@mui/material";
|
||||
import {toast} from "react-toastify";
|
||||
|
||||
const ErrorNotification = (directionApp, status, t, message) => {
|
||||
toast(
|
||||
() => (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "start",
|
||||
justifyContent: "start",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<DangerousIcon color="error" sx={{ mr: 1.6 }} />
|
||||
<Box sx={{ display: "flex", flexDirection: "column" }}>
|
||||
<Typography color="error" variant="button">
|
||||
{t("notifications.error")} ({t("notifications.code")}: {status})
|
||||
</Typography>
|
||||
<Typography variant="caption">
|
||||
{message || t("notifications.error_static_text")}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
),
|
||||
{
|
||||
position: directionApp === "ltr" ? "top-left" : "top-right",
|
||||
autoClose: false,
|
||||
closeOnClick: false,
|
||||
draggable: false,
|
||||
}
|
||||
);
|
||||
toast(
|
||||
() => (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "start",
|
||||
justifyContent: "start",
|
||||
}}
|
||||
>
|
||||
<Box sx={{display: "flex", alignItems: "center"}}>
|
||||
<DangerousIcon color="error" sx={{mr: 1.6}}/>
|
||||
<Box sx={{display: "flex", flexDirection: "column"}}>
|
||||
<Typography color="error" variant="button">
|
||||
{t("notifications.error")} ({t("notifications.code")}: {status})
|
||||
</Typography>
|
||||
<Typography variant="caption">
|
||||
{message || t("notifications.error_static_text")}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
),
|
||||
{
|
||||
position: directionApp === "ltr" ? "top-left" : "top-right",
|
||||
autoClose: false,
|
||||
closeOnClick: false,
|
||||
draggable: false,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default ErrorNotification;
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
import BeenhereIcon from "@mui/icons-material/Beenhere";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { toast } from "react-toastify";
|
||||
import {Box, Typography} from "@mui/material";
|
||||
import {toast} from "react-toastify";
|
||||
|
||||
const SuccessNotification = (directionApp, status, t) => {
|
||||
toast(
|
||||
() => (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "start",
|
||||
justifyContent: "start",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<BeenhereIcon color="success" sx={{ mr: 1.6 }} />
|
||||
<Box sx={{ display: "flex", flexDirection: "column" }}>
|
||||
<Typography color="success.main" variant="button">
|
||||
{t("notifications.success")} ({t("notifications.code")}:{" "}
|
||||
{status})
|
||||
</Typography>
|
||||
<Typography variant="caption">
|
||||
{t("notifications.success_static_text")}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
),
|
||||
{
|
||||
position: directionApp === "ltr" ? "top-left" : "top-right",
|
||||
autoClose: 3000,
|
||||
hideProgressBar: true,
|
||||
pauseOnHover: true,
|
||||
closeOnClick: false,
|
||||
draggable: true,
|
||||
}
|
||||
);
|
||||
toast(
|
||||
() => (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "start",
|
||||
justifyContent: "start",
|
||||
}}
|
||||
>
|
||||
<Box sx={{display: "flex", alignItems: "center"}}>
|
||||
<BeenhereIcon color="success" sx={{mr: 1.6}}/>
|
||||
<Box sx={{display: "flex", flexDirection: "column"}}>
|
||||
<Typography color="success.main" variant="button">
|
||||
{t("notifications.success")} ({t("notifications.code")}:{" "}
|
||||
{status})
|
||||
</Typography>
|
||||
<Typography variant="caption">
|
||||
{t("notifications.success_static_text")}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
),
|
||||
{
|
||||
position: directionApp === "ltr" ? "top-left" : "top-right",
|
||||
autoClose: 3000,
|
||||
hideProgressBar: true,
|
||||
pauseOnHover: true,
|
||||
closeOnClick: false,
|
||||
draggable: true,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default SuccessNotification;
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
import DangerousIcon from "@mui/icons-material/Dangerous";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { toast } from "react-toastify";
|
||||
import {Box, Typography} from "@mui/material";
|
||||
import {toast} from "react-toastify";
|
||||
|
||||
const UploadFileNotification = (directionApp, t) => {
|
||||
toast(
|
||||
({ closeToast }) => (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "start",
|
||||
justifyContent: "start",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<DangerousIcon color="error" sx={{ mr: 1.6 }} />
|
||||
<Box sx={{ display: "flex", flexDirection: "column" }}>
|
||||
<Typography color="error" variant="button">
|
||||
{t("UploadSystem.uploadfile_error")}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
),
|
||||
{
|
||||
position: directionApp === "ltr" ? "top-left" : "top-right",
|
||||
autoClose: false,
|
||||
closeOnClick: false,
|
||||
draggable: false,
|
||||
}
|
||||
);
|
||||
toast(
|
||||
({closeToast}) => (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "start",
|
||||
justifyContent: "start",
|
||||
}}
|
||||
>
|
||||
<Box sx={{display: "flex", alignItems: "center"}}>
|
||||
<DangerousIcon color="error" sx={{mr: 1.6}}/>
|
||||
<Box sx={{display: "flex", flexDirection: "column"}}>
|
||||
<Typography color="error" variant="button">
|
||||
{t("UploadSystem.uploadfile_error")}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
),
|
||||
{
|
||||
position: directionApp === "ltr" ? "top-left" : "top-right",
|
||||
autoClose: false,
|
||||
closeOnClick: false,
|
||||
draggable: false,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default UploadFileNotification;
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
import ReportIcon from "@mui/icons-material/Report";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { toast } from "react-toastify";
|
||||
import {Box, Typography} from "@mui/material";
|
||||
import {toast} from "react-toastify";
|
||||
|
||||
const WarningNotification = (directionApp, status, t) => {
|
||||
toast(
|
||||
() => (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "start",
|
||||
justifyContent: "start",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<ReportIcon color="warning" sx={{ mr: 1.6 }} />
|
||||
<Box sx={{ display: "flex", flexDirection: "column" }}>
|
||||
<Typography color="warning.main" variant="button">
|
||||
{t("notifications.warning")} ({t("notifications.code")}:{" "}
|
||||
{status})
|
||||
</Typography>
|
||||
<Typography variant="caption">
|
||||
{t("notifications.warning_static_text")}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
),
|
||||
{
|
||||
position: directionApp === "ltr" ? "top-left" : "top-right",
|
||||
autoClose: false,
|
||||
closeOnClick: false,
|
||||
draggable: false,
|
||||
}
|
||||
);
|
||||
toast(
|
||||
() => (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "start",
|
||||
justifyContent: "start",
|
||||
}}
|
||||
>
|
||||
<Box sx={{display: "flex", alignItems: "center"}}>
|
||||
<ReportIcon color="warning" sx={{mr: 1.6}}/>
|
||||
<Box sx={{display: "flex", flexDirection: "column"}}>
|
||||
<Typography color="warning.main" variant="button">
|
||||
{t("notifications.warning")} ({t("notifications.code")}:{" "}
|
||||
{status})
|
||||
</Typography>
|
||||
<Typography variant="caption">
|
||||
{t("notifications.warning_static_text")}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
),
|
||||
{
|
||||
position: directionApp === "ltr" ? "top-left" : "top-right",
|
||||
autoClose: false,
|
||||
closeOnClick: false,
|
||||
draggable: false,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default WarningNotification;
|
||||
|
||||
@@ -3,37 +3,37 @@ import WarningNotification from "./WarningNotification";
|
||||
import SuccessNotification from "./SuccessNotification";
|
||||
|
||||
const Notifications = async (directionApp, response, t) => {
|
||||
const { status, data } = response;
|
||||
const {status, data} = response;
|
||||
|
||||
switch (status) {
|
||||
case 200:
|
||||
SuccessNotification(directionApp, status, t);
|
||||
break;
|
||||
case 400:
|
||||
ErrorNotification(directionApp, status, t);
|
||||
break;
|
||||
case 401:
|
||||
ErrorNotification(directionApp, status, t);
|
||||
break;
|
||||
case 403:
|
||||
ErrorNotification(directionApp, status, t);
|
||||
break;
|
||||
case 422:
|
||||
ErrorNotification(directionApp, status, t, data.message);
|
||||
break;
|
||||
case 500:
|
||||
WarningNotification(directionApp, status, t);
|
||||
break;
|
||||
case 503:
|
||||
WarningNotification(directionApp, status, t);
|
||||
break;
|
||||
case 504:
|
||||
WarningNotification(directionApp, status, t);
|
||||
break;
|
||||
default:
|
||||
// Handle other cases if needed
|
||||
break;
|
||||
}
|
||||
switch (status) {
|
||||
case 200:
|
||||
SuccessNotification(directionApp, status, t);
|
||||
break;
|
||||
case 400:
|
||||
ErrorNotification(directionApp, status, t);
|
||||
break;
|
||||
case 401:
|
||||
ErrorNotification(directionApp, status, t);
|
||||
break;
|
||||
case 403:
|
||||
ErrorNotification(directionApp, status, t);
|
||||
break;
|
||||
case 422:
|
||||
ErrorNotification(directionApp, status, t, data.message);
|
||||
break;
|
||||
case 500:
|
||||
WarningNotification(directionApp, status, t);
|
||||
break;
|
||||
case 503:
|
||||
WarningNotification(directionApp, status, t);
|
||||
break;
|
||||
case 504:
|
||||
WarningNotification(directionApp, status, t);
|
||||
break;
|
||||
default:
|
||||
// Handle other cases if needed
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
export default Notifications;
|
||||
|
||||
Reference in New Issue
Block a user