Skip to content

Instantly share code, notes, and snippets.

@tripolskypetr
Created September 30, 2023 13:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tripolskypetr/62d737854e2b0d06d178fc030a62a822 to your computer and use it in GitHub Desktop.
Save tripolskypetr/62d737854e2b0d06d178fc030a62a822 to your computer and use it in GitHub Desktop.
import {
Async,
Center,
Chip,
LoaderView,
useAsyncAction,
} from "react-declarative";
import { forwardRef, useCallback, useMemo, useState } from "react";
import Box from "@mui/material/Box";
import { Button } from "@mui/material";
import { DEAL_STATUS_LIST } from "../../../../../../lib/services/db/DealDbService";
import {
DealStatus,
} from "../../../../../../lib/services/db/DealDbService";
import IDealCard from "../../../model/IDealCard";
import IconButton from "@mui/material/IconButton";
import KeyboardArrowLeft from "@mui/icons-material/KeyboardArrowLeft";
import KeyboardArrowRight from "@mui/icons-material/KeyboardArrowRight";
import Menu from "@mui/material/Menu";
import MenuItem from "@mui/material/MenuItem";
import Paper from "@mui/material/Paper";
import Typography from "@mui/material/Typography";
import clsx from "clsx";
import dayjs from "dayjs";
import ioc from "../../../../../../lib/ioc";
import { makeStyles } from "../../../../../../styles";
export const CARD_MIN_HEIGHT = 150;
const useStyles = makeStyles()((theme) => ({
root: {
display: "flex",
alignItems: "stretch",
justifyContent: "stretch",
flexDirection: "column",
minHeight: CARD_MIN_HEIGHT,
},
container: {
position: "relative",
display: "flex",
alignItems: "stretch",
justifyContent: "stretch",
flex: 1,
},
content: {
display: "flex",
alignItems: "stretch",
justifyContent: "stretch",
flexDirection: "column",
paddingTop: 6,
paddingBottom: 6,
gap: 6,
flex: 1,
},
header: {
display: "flex",
alignItems: "stretch",
justifyContent: "stretch",
flexDirection: "column",
paddingLeft: theme.spacing(0.5),
paddingRight: theme.spacing(0.5),
},
row: {
display: "flex",
alignItems: "center",
justifyContent: "space-between",
},
noBorder: {
border: "none !important",
},
bold: {
fontWeight: "bold !important",
},
adjust: {
maxHeight: 10,
minHeight: 10,
flex: 1,
},
button: {
backgroundColor: "#3F51B5",
color: "#ffffff",
fontSize: 12,
marginLeft: "auto",
marginRight: "auto",
"&:hover": {
color: "#3F51B5",
},
},
fieldContainer: {
display: "flex",
justifyContent: "space-between",
},
fieldDesc: {
fontSize: 10,
opacity: 0.6,
marginLeft: 4,
},
dateFieldDesc: {
fontSize: 8,
opacity: 0.6,
marginLeft: 4,
},
field: {
fontSize: 12,
marginRight: 4,
fontWeight: 500,
},
dateField: {
fontSize: 8,
},
}));
interface IDealCardProps extends IDealCard {
id: string;
className?: string;
style?: React.CSSProperties;
onChangeStatus: (dealStatus: DealStatus) => void;
onDrag: (id: string) => void;
}
export const DealCard = forwardRef(
(
{
className,
style,
contactDisplayName,
contactType,
contactNumber,
responsible,
requestType,
dealIndex,
dealType,
dealStatus,
price,
currency,
createdAt,
updatedAt,
apartmentId,
bidId,
id,
onChangeStatus,
onDrag,
}: IDealCardProps,
ref: React.Ref<HTMLDivElement>
) => {
const { classes } = useStyles();
const [beforeAnchorEl, setBeforeAnchorEl] =
useState<HTMLButtonElement | null>(null);
const [afterAnchorEl, setAfterAnchorEl] =
useState<HTMLButtonElement | null>(null);
const { execute: handleChangeStatus, loading } = useAsyncAction<void>(
async (payload) => {
await onChangeStatus(payload);
},
{
onLoadStart: () => ioc.layoutService.setAppbarLoader(true),
onLoadEnd: () => ioc.layoutService.setAppbarLoader(false),
fallback: ioc.errorService.handleGlobalError,
}
);
const beforeCurrentStatus = useMemo(() => {
const currentStatusIdx = DEAL_STATUS_LIST.findIndex(
(value) => value === dealStatus
);
return DEAL_STATUS_LIST.filter(
(_, idx) => idx < currentStatusIdx
).reverse();
}, [dealStatus]);
const afterCurrentStatus = useMemo(() => {
const currentStatusIdx = DEAL_STATUS_LIST.findIndex(
(value) => value === dealStatus
);
return DEAL_STATUS_LIST.filter((_, idx) => idx > currentStatusIdx);
}, [dealStatus]);
const createdDate = useMemo(() => {
return dayjs(createdAt).format("DD.MM.YYYY / HH:MM");
}, [createdAt]);
const updatedData = useMemo(() => {
return dayjs(updatedAt).format("DD.MM.YYYY / HH:MM");
}, [updatedAt]);
const readonly = useMemo(() => {
if (dealStatus === "Сделка сорвана") {
return true;
}
if (dealStatus === "Закрытая сделка") {
return true;
}
return false;
}, [dealStatus]);
const handleShowHistory = useCallback(() => {
if (apartmentId) {
ioc.routerService.push(`/apartment_view/${apartmentId}/history`);
return;
}
if (bidId) {
ioc.routerService.push(`/bid_view/${bidId}/history`);
return;
}
}, []);
return (
<div
data-dealid={id}
className={clsx(classes.root, className)}
onDrag={() => onDrag(id)}
style={style}
ref={ref}
draggable={!readonly}
>
<Paper className={classes.container}>
<Box className={classes.content}>
<Box className={classes.row}>
<IconButton
onClick={({ currentTarget }) => {
setBeforeAnchorEl(currentTarget);
setAfterAnchorEl(null);
}}
disabled={!beforeCurrentStatus.length || loading || readonly}
size="small"
>
<KeyboardArrowLeft />
</IconButton>
<Menu
anchorEl={beforeAnchorEl}
open={!!beforeAnchorEl}
onClose={() => setBeforeAnchorEl(null)}
>
{beforeCurrentStatus.map((status, idx) => (
<MenuItem
key={`${status}-${idx}`}
disabled={idx !== 0}
onClick={() => {
handleChangeStatus(status);
setBeforeAnchorEl(null);
}}
>
{status}
</MenuItem>
))}
</Menu>
<Chip
label={responsible}
variant="filled"
color="#2196F3"
sx={{
fontWeight: 500,
fontSize: 10,
}}
/>
<IconButton
onClick={({ currentTarget }) => {
setBeforeAnchorEl(null);
setAfterAnchorEl(currentTarget);
}}
disabled={!afterCurrentStatus.length || loading || readonly}
size="small"
>
<KeyboardArrowRight />
</IconButton>
<Menu
anchorEl={afterAnchorEl}
open={!!afterAnchorEl}
onClose={() => setAfterAnchorEl(null)}
>
{afterCurrentStatus.map((status, idx) => (
<MenuItem
key={`${status}-${idx}`}
disabled={idx !== 0}
onClick={() => {
handleChangeStatus(status);
setAfterAnchorEl(null);
}}
>
{status}
</MenuItem>
))}
</Menu>
</Box>
<Center sx={{ minHeight: 50 }}>
<Typography
fontSize={12}
textAlign="center"
maxWidth="80%"
paddingBottom="6px"
>
{contactDisplayName}
</Typography>
</Center>
{contactNumber && (
<Box className={classes.content}>
<Box
className={classes.fieldContainer}
sx={{ borderBottom: 1, borderColor: "#E0E0E0" }}
>
<Typography className={classes.fieldDesc}>
Тип контакта
</Typography>
<Typography className={classes.field}>
{contactType}
</Typography>
</Box>
<Box
className={classes.fieldContainer}
sx={{ borderBottom: 1, borderColor: "#E0E0E0" }}
>
<Typography className={classes.fieldDesc}>
Номер телефона
</Typography>
<Typography className={classes.field}>
{contactNumber}
</Typography>
</Box>
</Box>
)}
<Center>
<Box
sx={{
display: "flex",
flexWrap: "wrap",
justifyContent: "center",
maxWidth: "90%",
gap: 1,
}}
>
<Chip
label={`№ ${dealIndex}`}
variant="filled"
color="#E0E0E0"
/>
{dealType == "Аренда" ? (
<Chip
label="Аренда"
variant="filled"
color="#AF4C5E"
sx={{
color: "white",
}}
/>
) : (
<Chip
label="Продажа"
variant="filled"
color="#4CAFAF"
sx={{
color: "white",
}}
/>
)}
{requestType === "Заявка" ? (
<Chip
label="Заявка"
variant="filled"
color="#AFAB4C"
sx={{
color: "white",
}}
/>
) : (
<Chip
label="Объект"
variant="filled"
color="#4CAF50"
sx={{
color: "white",
}}
/>
)}
</Box>
</Center>
{price && (
<Box className={classes.content}>
<Box className={classes.fieldContainer}>
<Typography className={classes.fieldDesc}>
Цена {currency || "$"}
</Typography>
<Typography className={classes.field}>{price}</Typography>
</Box>
</Box>
)}
<Box
className={classes.container}
sx={{ borderTop: 1, borderColor: "#E0E0E0" }}
>
<Center className={classes.content}>
<Typography className={classes.dateFieldDesc}>
Дата создания:
</Typography>
<Typography className={classes.dateField}>
{createdDate}
</Typography>
</Center>
<Center className={classes.content}>
<Typography className={classes.dateFieldDesc}>
Дата обновления:
</Typography>
<Typography className={classes.dateField}>
{updatedData}
</Typography>
</Center>
</Box>
<Button onClick={handleShowHistory} variant="outlined" sx={{ ml: 1, mr: 1 }}>Посмотреть историю</Button>
</Box>
</Paper>
<div className={classes.adjust} />
</div>
);
}
) as React.FC<IDealCardProps>;
export default DealCard;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment