EqualltyChoiceBottomSheet: update UI

This commit is contained in:
2025-12-17 01:05:02 +03:00
parent c369807f40
commit 9a3608d5ab
5 changed files with 215 additions and 152 deletions

View File

@@ -1,7 +1,7 @@
.quantityControls { .quantityControls {
display: flex; display: flex;
align-items: center; align-items: center;
background-color: #ffb70014; background-color: var(--background);
border-radius: 888px; border-radius: 888px;
width: fit-content; width: fit-content;
} }
@@ -15,7 +15,7 @@
.quantityInputContainer { .quantityInputContainer {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 8px; padding: 0 1px;
border-radius: 888px; border-radius: 888px;
width: 100px; width: 100px;
height: 32px; height: 32px;
@@ -78,6 +78,11 @@
.plusIcon { .plusIcon {
margin-bottom: 1px; margin-bottom: 1px;
color: var(--secondary-background);
}
.minusIcon {
color: var(--secondary-foreground);
} }
.deleteIcon { .deleteIcon {

View File

@@ -1,7 +1,6 @@
import { MinusOutlined } from "@ant-design/icons"; import { MinusOutlined, PlusOutlined } from "@ant-design/icons";
import { Button, Grid, InputNumber, Popconfirm } from "antd"; import { Button, Grid, InputNumber, Popconfirm } from "antd";
import DeleteIcon from "components/Icons/DeleteIcon"; import DeleteIcon from "components/Icons/DeleteIcon";
import PlusIcon from "components/Icons/PlusIcon";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useAppSelector } from "redux/hooks"; import { useAppSelector } from "redux/hooks";
import { colors } from "../../ThemeConstants"; import { colors } from "../../ThemeConstants";
@@ -51,14 +50,19 @@ export default function ActionsButtons({
<div className={styles.quantityInputContainer}> <div className={styles.quantityInputContainer}>
{quantity > 0 ? ( {quantity > 0 ? (
<Button <Button
type="text" shape="circle"
iconPlacement="start"
icon={<MinusOutlined title="add" className={styles.minusIcon} />}
size="small" size="small"
onClick={() => setQuantity(Math.max(1, quantity - 1))} onClick={() => setQuantity(Math.max(1, quantity - 1))}
className={styles.quantityButton} className={styles.quantityButton}
{...(min && { disabled: quantity === min })} {...(min && { disabled: quantity === min })}
> style={{
<MinusOutlined style={{ fontSize: 16, color: colors.primary }} /> width: 28,
</Button> height: 28,
border: "none",
}}
/>
) : ( ) : (
<Popconfirm <Popconfirm
title={t("cart.deleteConfirmation.title")} title={t("cart.deleteConfirmation.title")}
@@ -70,17 +74,20 @@ export default function ActionsButtons({
placement={isRTL ? "left" : "right"} placement={isRTL ? "left" : "right"}
styles={{ styles={{
root: getPopconfirmOverlayStyle(), root: getPopconfirmOverlayStyle(),
body: {
padding: xs ? "12px" : "16px",
},
}} }}
> >
<Button <Button
type="text" shape="circle"
iconPlacement="start"
icon={<DeleteIcon />}
size="small" size="small"
danger className={styles.addButton}
icon={<DeleteIcon className={styles.deleteIcon} />} style={{
className={styles.removeButton} background: "#FEF2F2",
width: 28,
height: 28,
border: "none",
}}
/> />
</Popconfirm> </Popconfirm>
)} )}
@@ -88,21 +95,27 @@ export default function ActionsButtons({
min={min || 1} min={min || 1}
max={max || 100} max={max || 100}
value={quantity || 1} value={quantity || 1}
onChange={(value) => setQuantity(value || 1)} onChange={(value: number | null) => setQuantity(value || 1)}
size="small" size="small"
controls={false} controls={false}
className={styles.quantityInput} className={styles.quantityInput}
name="id" name="id"
/> />
<Button <Button
type="text" shape="circle"
iconPlacement="start"
icon={<PlusOutlined title="add" className={styles.plusIcon} />}
size="small" size="small"
onClick={() => setQuantity(Math.min(100, quantity + 1))} onClick={() => setQuantity(Math.min(100, quantity + 1))}
className={styles.quantityButton} className={styles.quantityButton}
{...(max && { disabled: quantity >= max })} {...(max && { disabled: quantity >= max })}
> style={{
<PlusIcon className={styles.plusIcon} /> backgroundColor: colors.primary,
</Button> width: 28,
height: 28,
border: "none",
}}
/>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -56,7 +56,6 @@
position: absolute; position: absolute;
top: 12px; top: 12px;
right: 12px; right: 12px;
background-color: #ffb70014;
border-radius: 50%; border-radius: 50%;
padding: 8px; padding: 8px;
cursor: pointer; cursor: pointer;

View File

@@ -46,7 +46,7 @@ export default function CartActionsButtons({ item }: { item: CartItem }) {
{item.quantity > 1 ? ( {item.quantity > 1 ? (
<Button <Button
shape="circle" shape="circle"
iconPosition="start" iconPlacement="start"
icon={<MinusOutlined title="add" className={styles.minusIcon} />} icon={<MinusOutlined title="add" className={styles.minusIcon} />}
size="small" size="small"
onClick={() => onClick={() =>
@@ -76,14 +76,11 @@ export default function CartActionsButtons({ item }: { item: CartItem }) {
placement={isRTL ? "left" : "right"} placement={isRTL ? "left" : "right"}
styles={{ styles={{
root: getPopconfirmOverlayStyle(), root: getPopconfirmOverlayStyle(),
body: {
padding: isMobile ? "12px" : "16px",
},
}} }}
> >
<Button <Button
shape="circle" shape="circle"
iconPosition="start" iconPlacement="start"
icon={<DeleteIcon />} icon={<DeleteIcon />}
size="small" size="small"
onClick={() => onClick={() =>
@@ -109,7 +106,7 @@ export default function CartActionsButtons({ item }: { item: CartItem }) {
min={1} min={1}
max={100} max={100}
value={item.quantity || 1} value={item.quantity || 1}
onChange={(value: number) => onChange={(value: number | null) =>
dispatch( dispatch(
updateQuantity({ updateQuantity({
id: item.id, id: item.id,
@@ -125,7 +122,7 @@ export default function CartActionsButtons({ item }: { item: CartItem }) {
/> />
<Button <Button
shape="circle" shape="circle"
iconPosition="start" iconPlacement="start"
icon={<PlusOutlined title="add" className={styles.plusIcon} />} icon={<PlusOutlined title="add" className={styles.plusIcon} />}
size="small" size="small"
onClick={() => onClick={() =>

View File

@@ -3,8 +3,8 @@ import { ProBottomSheet } from "components/ProBottomSheet/ProBottomSheet.tsx";
import { useMemo } from "react"; import { useMemo } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import PeopleIcon from "components/Icons/PeopleIcon";
import ProText from "components/ProText"; import ProText from "components/ProText";
import ArabicPrice from "components/ArabicPrice";
import { import {
selectCart, selectCart,
selectGrandTotal, selectGrandTotal,
@@ -14,6 +14,7 @@ import { useAppDispatch, useAppSelector } from "redux/hooks";
import { ProGray1 } from "ThemeConstants"; import { ProGray1 } from "ThemeConstants";
import PayForActions from "../../../split-bill/components/PayForActions"; import PayForActions from "../../../split-bill/components/PayForActions";
import TotalPeopleActions from "../../../split-bill/components/TotalPeopleActions"; import TotalPeopleActions from "../../../split-bill/components/TotalPeopleActions";
import styles from "./SplitBill.module.css";
interface SplitBillChoiceBottomSheetProps { interface SplitBillChoiceBottomSheetProps {
isOpen: boolean; isOpen: boolean;
@@ -34,20 +35,23 @@ export function EqualltyChoiceBottomSheet({
}: SplitBillChoiceBottomSheetProps) { }: SplitBillChoiceBottomSheetProps) {
const { t } = useTranslation(); const { t } = useTranslation();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { tmp } = useAppSelector(selectCart); const { tmp, splitBillAmount } = useAppSelector(selectCart);
const grandTotal = useAppSelector(selectGrandTotal); const grandTotal = useAppSelector(selectGrandTotal);
const splitBillTmp = tmp as SplitBillTmp; const splitBillTmp = tmp as SplitBillTmp;
const totalPeople = splitBillTmp?.totalPeople || 2; const totalPeople = splitBillTmp?.totalPeople || 2;
const payFor = splitBillTmp?.payFor || 1; const payFor = splitBillTmp?.payFor || 1;
// Calculate split amount // Calculate original total bill (grandTotal already subtracts splitBillAmount)
const originalTotalBill = grandTotal + splitBillAmount;
// Calculate split amount based on original total bill
const splitAmount = useMemo(() => { const splitAmount = useMemo(() => {
if (totalPeople > 0) { if (totalPeople > 0) {
return (grandTotal / totalPeople) * payFor; return (originalTotalBill / totalPeople) * payFor;
} }
return 0; return 0;
}, [grandTotal, totalPeople, payFor]); }, [originalTotalBill, totalPeople, payFor]);
const handleSave = () => { const handleSave = () => {
dispatch(updateSplitBillAmount(splitAmount)); dispatch(updateSplitBillAmount(splitAmount));
@@ -67,8 +71,11 @@ export function EqualltyChoiceBottomSheet({
title={t("splitBill.divideTheBillEqually")} title={t("splitBill.divideTheBillEqually")}
showCloseButton={true} showCloseButton={true}
initialSnap={1} initialSnap={1}
height={610} height={630}
snapPoints={[610]} snapPoints={[630]}
contentStyle={{
padding: 0,
}}
> >
<div <div
style={{ style={{
@@ -77,96 +84,6 @@ export function EqualltyChoiceBottomSheet({
marginTop: 20, marginTop: 20,
}} }}
> >
<div
style={{
display: "flex",
flexDirection: "column",
gap: "1rem",
}}
>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
gap: "1rem",
padding: 8,
}}
>
<div
style={{
display: "flex",
flexDirection: "row",
gap: "1rem",
}}
>
<Button
type="text"
shape="circle"
style={{
backgroundColor: "rgba(95, 108, 123, 0.05)",
position: "relative",
top: -10,
}}
>
<PeopleIcon />
</Button>
<ProText
style={{
fontSize: "1rem",
marginTop: 3,
color: ProGray1,
}}
>
{t("checkout.totalPeople")}
</ProText>
</div>
<TotalPeopleActions />
</div>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
gap: "1rem",
padding: 8,
}}
>
<div
style={{
display: "flex",
flexDirection: "row",
gap: "1rem",
}}
>
<Button
type="text"
shape="circle"
style={{
backgroundColor: "rgba(95, 108, 123, 0.05)",
position: "relative",
top: -10,
}}
>
<PeopleIcon />
</Button>
<ProText
style={{
fontSize: "1rem",
marginTop: 2,
color: ProGray1,
}}
>
{t("checkout.payFor")}
</ProText>
</div>
<PayForActions />
</div>
</div>
{/* Spinner Visualization - Blank Spin Wheel */} {/* Spinner Visualization - Blank Spin Wheel */}
{totalPeople > 0 && ( {totalPeople > 0 && (
<div <div
@@ -203,7 +120,7 @@ export function EqualltyChoiceBottomSheet({
const startAngleRad = (startAngle * Math.PI) / 180; const startAngleRad = (startAngle * Math.PI) / 180;
const endAngleRad = (endAngle * Math.PI) / 180; const endAngleRad = (endAngle * Math.PI) / 180;
// Calculate path for pie slice // Calculate path for pie slice (fit 200x200 viewBox)
const radius = 90; const radius = 90;
const centerX = 100; const centerX = 100;
const centerY = 100; const centerY = 100;
@@ -230,57 +147,189 @@ export function EqualltyChoiceBottomSheet({
isSelected ? "var(--primary)" : "rgba(0, 0, 0, 0.1)" isSelected ? "var(--primary)" : "rgba(0, 0, 0, 0.1)"
} }
stroke="#fff" stroke="#fff"
strokeWidth="2" strokeWidth="5"
/> />
); );
})} })}
</svg> </svg>
{/* Center circle to make it look like a blank wheel */} {/* Center circle with total bill amount */}
<div <div
style={{ style={{
position: "absolute", position: "absolute",
top: "50%", top: "50%",
left: "50%", left: "50%",
transform: "translate(-50%, -50%)", transform: "translate(-50%, -50%)",
width: 60, // Keep the SVG at 200x200, but make the center content smaller
height: 60, // so the wheel remains visible around it.
width: 160,
height: 160,
borderRadius: "50%", borderRadius: "50%",
backgroundColor: "var(--background)", backgroundColor: "var(--secondary-background)",
border: "3px solid var(--primary)",
display: "flex", display: "flex",
flexDirection: "column",
alignItems: "center", alignItems: "center",
justifyContent: "center", justifyContent: "center",
fontSize: 18,
fontWeight: 600,
color: "var(--primary)",
zIndex: 10, zIndex: 10,
padding: 10,
}} }}
> >
{payFor} <div
</div> style={{
fontSize: 20,
fontWeight: 600,
color: "var(--primary)",
lineHeight: 1.1,
textAlign: "center",
}}
>
<ArabicPrice
price={originalTotalBill}
style={{
fontSize: 20,
fontWeight: 600,
}}
/>
</div> </div>
<ProText <ProText
style={{ style={{
fontSize: 11,
color: ProGray1,
marginTop: 6,
textAlign: "center", textAlign: "center",
marginTop: 12, lineHeight: 1.2,
fontSize: 16, fontWeight: 400,
fontWeight: 600,
}} }}
> >
{t("splitBill.yourAmount")}: {splitAmount.toFixed(2)} {t("splitBill.totalBill")}
</ProText> </ProText>
</div> </div>
</div>
</div>
)} )}
<div <div
style={{ style={{
display: "flex", display: "flex",
gap: 12, flexDirection: "column",
marginTop: 20, gap: "1rem",
padding: 20,
}} }}
> >
<Button style={{ flex: 1 }} onClick={handleRemoveSplitWay}> <div
{t("splitBill.removeSplitWay")} style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
gap: "1rem",
padding: 8,
}}
>
<ProText
style={{
fontSize: "1rem",
marginTop: 3,
color: ProGray1,
}}
>
{t("checkout.totalPeople")}
</ProText>
<TotalPeopleActions />
<ProText
style={{
fontSize: "1rem",
marginTop: 3,
color: ProGray1,
}}
>
{t("checkout.totalPeople")}
</ProText>
</div>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
gap: "1rem",
padding: 8,
}}
>
<ProText
style={{
fontSize: "1rem",
marginTop: 2,
color: ProGray1,
}}
>
{t("checkout.payFor")}
</ProText>
<PayForActions />
<ProText
style={{
fontSize: "1rem",
marginTop: 2,
color: ProGray1,
}}
>
{t("checkout.payFor")}
</ProText>
</div>
</div>
<div
style={{
display: "flex",
flexDirection: "column",
backgroundColor: "var(--background)",
padding: 20,
opacity: 1,
gap: 8,
borderTopLeftRadius: 24,
borderTopRightRadius: 24,
paddingTop: 12,
paddingRight: 24,
paddingBottom: 24,
paddingLeft: 24,
}}
>
<div className={styles.summaryRow}>
<ProText
style={{
fontWeight: 400,
fontStyle: "Regular",
fontSize: 14,
lineHeight: "140%",
letterSpacing: "0%",
}}
>
{t("splitBill.yourShare")}
</ProText>
<ArabicPrice price={splitAmount} />
</div>
</div>
<div
style={{
display: "flex",
gap: 12,
margin: 20,
}}
>
<Button
style={{
flex: 1,
backgroundColor: "#FEEDED",
color: "#DD4143",
boxShadow: "none",
border: "none",
}}
onClick={handleRemoveSplitWay}
>
{t("splitBill.removeSplit")}
</Button> </Button>
<Button <Button
type="primary" type="primary"