apply rate feature

This commit is contained in:
2025-11-24 00:46:14 +03:00
parent 6e8305f9c2
commit 7e5a5e30a4
7 changed files with 1074 additions and 36 deletions

View File

@@ -1,33 +1,49 @@
.homeServiceCard {
width: 100%;
height: 48px;
display: flex;
justify-content: flex-start;
padding: 12px 18px !important;
row-gap: 10px;
transition: all 0.3s ease;
border-radius: 50px;
background-color: rgba(234, 31, 34, 0.04);
color: #ea1f22;
}
.homeServiceCard :global(.ant-card-body) {
padding: 0px !important;
text-align: start;
width: 100%;
}
.serviceIcon path {
stroke: #ea1f22;
}
width: 100%;
height: 48px;
display: flex;
justify-content: flex-start;
padding: 12px 18px !important;
row-gap: 10px;
transition: all 0.3s ease;
border-radius: 50px;
background-color: rgba(234, 31, 34, 0.04);
color: #ea1f22;
}
.nextIcon {
width: 24px;
height: 24px;
}
.homeServiceCard :global(.ant-card-body) {
padding: 0px !important;
text-align: start;
width: 100%;
}
.backIcon {
width: 24px;
height: 24px;
}
.rateServiceCard{
width: 100%;
height: 48px;
display: flex;
justify-content: center;
padding: 12px 18px !important;
row-gap: 10px;
transition: all 0.3s ease;
border-radius: 50px;
}
.rateServiceCard :global(.ant-card-body) {
padding: 0px !important;
text-align: start;
width: 100%;
}
.serviceIcon path {
stroke: #ea1f22;
}
.nextIcon {
width: 24px;
height: 24px;
}
.backIcon {
width: 24px;
height: 24px;
}

View File

@@ -0,0 +1,239 @@
// import { useGlobals } from "../../hooks/useGlobals";
import { Button, Card, message } from "antd";
import BackIcon from "components/Icons/BackIcon";
import NextIcon from "components/Icons/NextIcon";
import RateIcon from "components/Icons/order/RateIcon";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useParams } from "react-router-dom";
import { useGetUserDetailsQuery, useRateOrderMutation } from "redux/api/others";
import { useAppSelector } from "redux/hooks";
import { ProBottomSheet } from "../ProBottomSheet/ProBottomSheet";
import ProText from "../ProText";
import ProTitle from "../ProTitle";
import styles from "./CustomBottomSheet.module.css";
import { colors } from "ThemeConstants";
export function RateBottomSheet() {
const { t } = useTranslation();
const [isOpen, setIsOpen] = useState(false);
const [rating, setRating] = useState<number>(0);
const { isRTL } = useAppSelector((state) => state.locale);
const { orderId } = useParams();
const [rateOrder] = useRateOrderMutation();
const { data: getUserDetails } = useGetUserDetailsQuery(undefined, {
skip: !isOpen,
});
const handleSubmitRating = () => {
setIsOpen(false);
rateOrder({
orderID: orderId || "",
rating: rating,
comment: "This is a test comment",
userID: getUserDetails?.id.toString() || "",
}).then((res: any) => {
if (res.error) {
message.error(res.error.data.message);
} else {
message.success(res.data.message);
}
});
};
const handleStarClick = (
starIndex: number,
event: React.MouseEvent<HTMLDivElement>,
) => {
const starElement = event.currentTarget;
const rect = starElement.getBoundingClientRect();
const clickX = event.clientX - rect.left;
const starWidth = rect.width;
// Calculate which part of the star was clicked
// Divide star into 4 parts: 0-25% = 0.25, 25-50% = 0.5, 50-75% = 0.75, 75-100% = 1.0
const clickPercentage = clickX / starWidth;
let starValue = 0;
if (clickPercentage <= 0.25) {
starValue = 0.25;
} else if (clickPercentage <= 0.5) {
starValue = 0.5;
} else if (clickPercentage <= 0.75) {
starValue = 0.75;
} else {
starValue = 1.0;
}
const newRating = starIndex + starValue;
setRating(Math.min(newRating, 5)); // Cap at 5
};
return (
<>
<Card className={styles.rateServiceCard} onClick={() => setIsOpen(true)}>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "center",
marginTop: 1,
}}
>
<div style={{ display: "flex", flexDirection: "row", gap: 10 }}>
<ProTitle
level={5}
style={{
marginTop: 1,
fontSize: 14,
}}
>
{t("order.rateOrder")}
</ProTitle>
</div>
</div>
</Card>
<ProBottomSheet
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title={t("order.rateOrder")}
showCloseButton={false}
initialSnap={1}
height={450}
snapPoints={[450]}
>
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
gap: 16,
marginTop: 15,
}}
>
<RateIcon />
<ProText
style={{
fontSize: 14,
}}
>
{t("order.howWasYourExperienceWithFascanoRestaurant")}
</ProText>
<div
style={{
display: "flex",
flexDirection: "row",
gap: 8,
marginTop: 10,
marginBottom: 10,
}}
>
{[0, 1, 2, 3, 4].map((starIndex) => {
const starValue = starIndex + 1;
const isFilled = rating >= starValue;
const isPartialFilled = rating > starIndex && rating < starValue;
const fillPercentage = isPartialFilled
? ((rating - starIndex) * 100) / 1
: isFilled
? 100
: 0;
return (
<div
key={starIndex}
onClick={(e) => handleStarClick(starIndex, e)}
style={{
position: "relative",
cursor: "pointer",
width: 40,
height: 40,
display: "inline-block",
}}
>
{/* Gray star background */}
<svg
width="40"
height="40"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
style={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
}}
>
<path
d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z"
fill="#d3d3d3"
/>
</svg>
{/* Golden star overlay with overflow for partial fill */}
<div
style={{
position: "absolute",
top: 0,
left: 0,
width: `${fillPercentage}%`,
height: "100%",
overflow: "hidden",
}}
>
<svg
width="40"
height="40"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
style={{
position: "absolute",
top: 0,
left: 0,
width: 40,
height: 40,
}}
>
<path
d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z"
fill={colors.primary}
/>
</svg>
</div>
</div>
);
})}
</div>
<div
style={{
display: "flex",
flexDirection: "row",
gap: 10,
width: "100%",
}}
>
<Button
type="primary"
style={{
width: "100%",
height: 50,
color: colors.primary,
borderColor: colors.primary,
backgroundColor: "#fff",
}}
onClick={handleSubmitRating}
>
{t("order.submitRating")}
</Button>
</div>
</div>
</ProBottomSheet>
</>
);
}