Skip to content

Commit

Permalink
refactor: extract shared order filtering logic into custom hook
Browse files Browse the repository at this point in the history
  • Loading branch information
derianrddev committed Nov 23, 2024
1 parent e02b53b commit e9e3c8c
Show file tree
Hide file tree
Showing 4 changed files with 199 additions and 172 deletions.
100 changes: 25 additions & 75 deletions apps/web/src/app/user/my-orders/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,13 @@ import { zodResolver } from "@hookform/resolvers/zod";
import Button from "@repo/ui/button";
import CheckBox from "@repo/ui/form/checkBox";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";
import OrderListItem from "~/app/_components/features/OrderListItem";
import { ProfileOptionLayout } from "~/app/_components/features/ProfileOptionLayout";
import BottomModal from "~/app/_components/ui/BottomModal";

const SalesStatusEnum = {
Paid: "Paid",
Prepared: "Prepared",
Shipped: "Shipped",
Delivered: "Delivered",
} as const;

type SalesStatus = (typeof SalesStatusEnum)[keyof typeof SalesStatusEnum];
import { useOrderFiltering } from "~/hooks/user/useOrderFiltering";
import { type SalesStatus, SalesStatusEnum } from "~/types/user/order";

const filtersSchema = z.object({
statusPaid: z.boolean().optional(),
Expand Down Expand Up @@ -67,80 +59,38 @@ const mockedOrders = [
},
];

const filtersDefaults = {
statusPaid: false,
statusPrepared: false,
statusShipped: false,
statusDelivered: false,
};

export default function MyOrders() {
const [searchTerm, setSearchTerm] = useState("");
const [isFiltersModalOpen, setIsFiltersModalOpen] = useState(false);
const [filteredOrders, setFilteredOrders] = useState(mockedOrders);
const [activeFilters, setActiveFilters] = useState<FormValues>({});
const {
searchTerm,
setSearchTerm,
isFiltersModalOpen,
openFiltersModal,
closeFiltersModal,
filteredOrders,
applyFilters,
} = useOrderFiltering({
orders: mockedOrders,
searchKey: "sellerName",
filters: filtersDefaults,
});
const router = useRouter();

const openFiltersModal = () => {
setIsFiltersModalOpen(true);
};

const closeFiltersModal = () => {
setIsFiltersModalOpen(false);
};

const { control, handleSubmit } = useForm<FormValues>({
resolver: zodResolver(filtersSchema),
defaultValues: {
statusPaid: false,
statusPrepared: false,
statusShipped: false,
statusDelivered: false,
},
defaultValues: filtersDefaults,
});

const onSubmit = (data: FormValues) => {
console.log(data);
setActiveFilters(data);
closeFiltersModal();
};

const handleItemClick = (id: string) => {
router.push(`/user/my-orders/${id}`);
};

useEffect(() => {
const newFilteredOrders = mockedOrders
.map((orderGroup) => ({
...orderGroup,
items: orderGroup.items.filter((item) => {
const matchesSearch = searchTerm
? item.sellerName.toLowerCase().includes(searchTerm.toLowerCase())
: true;

const activeStatusFilters = [
activeFilters.statusPaid,
activeFilters.statusPrepared,
activeFilters.statusShipped,
activeFilters.statusDelivered,
];

const matchesStatus = activeStatusFilters.some(Boolean)
? (activeFilters.statusPaid &&
item.status === SalesStatusEnum.Paid) ??
(activeFilters.statusPrepared &&
item.status === SalesStatusEnum.Prepared) ??
(activeFilters.statusShipped &&
item.status === SalesStatusEnum.Shipped) ??
(activeFilters.statusDelivered &&
item.status === SalesStatusEnum.Delivered)
: true;

return matchesSearch && matchesStatus;
}),
}))
.filter((orderGroup) => orderGroup.items.length > 0);

if (!searchTerm && !Object.values(activeFilters).some(Boolean)) {
setFilteredOrders(mockedOrders);
} else {
setFilteredOrders(newFilteredOrders);
}
}, [searchTerm, activeFilters]);

return (
<ProfileOptionLayout title="My orders">
<div className="bg-white rounded-lg p-6 space-y-6">
Expand Down Expand Up @@ -175,7 +125,7 @@ export default function MyOrders() {
<OrderListItem
key={`${order.productName}-${orderIndex}`}
productName={order.productName}
name={order.sellerName}
name={order.sellerName ?? "unknown_seller"}
status={order.status}
onClick={() => handleItemClick(order.id)}
/>
Expand All @@ -190,7 +140,7 @@ export default function MyOrders() {
</div>

<BottomModal isOpen={isFiltersModalOpen} onClose={closeFiltersModal}>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
<form onSubmit={handleSubmit(applyFilters)} className="space-y-4">
<h3 className="text-xl font-semibold my-4 text-content-title">
Status
</h3>
Expand Down
129 changes: 32 additions & 97 deletions apps/web/src/app/user/my-sales/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,18 @@ import { zodResolver } from "@hookform/resolvers/zod";
import Button from "@repo/ui/button";
import CheckBox from "@repo/ui/form/checkBox";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";
import OrderListItem from "~/app/_components/features/OrderListItem";
import { ProfileOptionLayout } from "~/app/_components/features/ProfileOptionLayout";
import BottomModal from "~/app/_components/ui/BottomModal";

const SalesStatusEnum = {
Paid: "Paid",
Prepared: "Prepared",
Shipped: "Shipped",
Delivered: "Delivered",
} as const;

type SalesStatus = (typeof SalesStatusEnum)[keyof typeof SalesStatusEnum];

const DeliveryMethodEnum = {
Address: "Address",
Meetup: "Meetup",
} as const;

type DeliveryMethod =
(typeof DeliveryMethodEnum)[keyof typeof DeliveryMethodEnum];
import { useOrderFiltering } from "~/hooks/user/useOrderFiltering";
import {
type DeliveryMethod,
DeliveryMethodEnum,
type SalesStatus,
SalesStatusEnum,
} from "~/types/user/order";

const filtersSchema = z.object({
statusPaid: z.boolean().optional(),
Expand Down Expand Up @@ -81,94 +70,40 @@ const mockedOrders = [
},
];

const filtersDefaults = {
statusPaid: false,
statusPrepared: false,
statusShipped: false,
statusDelivered: false,
deliveryAddress: false,
deliveryMeetup: false,
};

export default function MySales() {
const [searchTerm, setSearchTerm] = useState("");
const [isFiltersModalOpen, setIsFiltersModalOpen] = useState(false);
const [filteredOrders, setFilteredOrders] = useState(mockedOrders);
const [activeFilters, setActiveFilters] = useState<FormValues>({});
const {
searchTerm,
setSearchTerm,
isFiltersModalOpen,
openFiltersModal,
closeFiltersModal,
filteredOrders,
applyFilters,
} = useOrderFiltering({
orders: mockedOrders,
searchKey: "buyerName",
filters: filtersDefaults,
});
const router = useRouter();

const openFiltersModal = () => {
setIsFiltersModalOpen(true);
};

const closeFiltersModal = () => {
setIsFiltersModalOpen(false);
};

const { control, handleSubmit } = useForm<FormValues>({
resolver: zodResolver(filtersSchema),
defaultValues: {
statusPaid: false,
statusPrepared: false,
statusShipped: false,
statusDelivered: false,
deliveryAddress: false,
deliveryMeetup: false,
},
defaultValues: filtersDefaults,
});

const onSubmit = (data: FormValues) => {
console.log(data);
setActiveFilters(data);
closeFiltersModal();
};

const handleItemClick = (id: string) => {
router.push(`/user/my-sales/${id}`);
};

useEffect(() => {
const newFilteredOrders = mockedOrders
.map((orderGroup) => ({
...orderGroup,
items: orderGroup.items.filter((item) => {
const matchesSearch = searchTerm
? item.buyerName.toLowerCase().includes(searchTerm.toLowerCase())
: true;

const activeStatusFilters = [
activeFilters.statusPaid,
activeFilters.statusPrepared,
activeFilters.statusShipped,
activeFilters.statusDelivered,
];

const matchesStatus = !activeStatusFilters.some(Boolean)
? true
: (activeFilters.statusPaid &&
item.status === SalesStatusEnum.Paid) ??
(activeFilters.statusPrepared &&
item.status === SalesStatusEnum.Prepared) ??
(activeFilters.statusShipped &&
item.status === SalesStatusEnum.Shipped) ??
(activeFilters.statusDelivered &&
item.status === SalesStatusEnum.Delivered);

const activeDeliveryFilters = [
activeFilters.deliveryAddress,
activeFilters.deliveryMeetup,
];

const matchesDelivery = !activeDeliveryFilters.some(Boolean)
? true
: (activeFilters.deliveryAddress &&
item.delivery === DeliveryMethodEnum.Address) ??
(activeFilters.deliveryMeetup &&
item.delivery === DeliveryMethodEnum.Meetup);

return matchesSearch && matchesStatus && matchesDelivery;
}),
}))
.filter((orderGroup) => orderGroup.items.length > 0);

if (!searchTerm && !Object.values(activeFilters).some(Boolean)) {
setFilteredOrders(mockedOrders);
} else {
setFilteredOrders(newFilteredOrders);
}
}, [searchTerm, activeFilters]);

return (
<ProfileOptionLayout title="My Sellers">
<div className="bg-white rounded-lg p-6 space-y-6">
Expand Down Expand Up @@ -203,7 +138,7 @@ export default function MySales() {
<OrderListItem
key={`${order.productName}-${orderIndex}`}
productName={order.productName}
name={order.buyerName}
name={order.buyerName ?? "unknown_buyer"}
status={order.status}
onClick={() => handleItemClick(order.id)}
/>
Expand All @@ -218,7 +153,7 @@ export default function MySales() {
</div>

<BottomModal isOpen={isFiltersModalOpen} onClose={closeFiltersModal}>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
<form onSubmit={handleSubmit(applyFilters)} className="space-y-4">
<h3 className="text-xl font-semibold my-4 text-content-title">
Delivery method
</h3>
Expand Down
Loading

0 comments on commit e9e3c8c

Please sign in to comment.