151 lines
5.6 KiB
TypeScript
151 lines
5.6 KiB
TypeScript
"use client";
|
|
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import { Button } from "@workspace/ui/components/button";
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardFooter,
|
|
CardHeader,
|
|
} from "@workspace/ui/components/card";
|
|
import { Separator } from "@workspace/ui/components/separator";
|
|
import Empty from "@workspace/ui/composed/empty";
|
|
import { Icon } from "@workspace/ui/composed/icon";
|
|
import { cn } from "@workspace/ui/lib/utils";
|
|
import { querySubscribeList } from "@workspace/ui/services/user/subscribe";
|
|
import { useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { Display } from "@/components/display";
|
|
import { SubscribeDetail } from "./detail";
|
|
import Purchase from "./purchase";
|
|
|
|
export default function Subscribe() {
|
|
const { t, i18n } = useTranslation("subscribe");
|
|
const unitTimeMap: Record<string, string> = {
|
|
Day: t("Day", "Day"),
|
|
Hour: t("Hour", "Hour"),
|
|
Minute: t("Minute", "Minute"),
|
|
Month: t("Month", "Month"),
|
|
NoLimit: t("NoLimit", "No Limit"),
|
|
Year: t("Year", "Year"),
|
|
};
|
|
const locale = i18n.language;
|
|
const [subscribe, setSubscribe] = useState<API.Subscribe>();
|
|
|
|
const { data } = useQuery({
|
|
queryKey: ["querySubscribeList", locale],
|
|
queryFn: async () => {
|
|
console.log("Fetching subscription list...");
|
|
const { data } = await querySubscribeList({ language: locale });
|
|
return data.data?.list || [];
|
|
},
|
|
});
|
|
|
|
const filteredData = data?.filter((item) => item.show);
|
|
|
|
return (
|
|
<>
|
|
<div className="space-y-4">
|
|
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3">
|
|
{filteredData?.map((item) => (
|
|
<Card className="relative flex flex-col" key={item.id}>
|
|
<CardHeader className="font-medium text-xl">
|
|
{item.name}
|
|
</CardHeader>
|
|
<CardContent className="*:!text-sm flex flex-grow flex-col gap-3">
|
|
{/* <div className='font-semibold'>{t('productDescription')}</div> */}
|
|
<ul className="flex flex-grow flex-col gap-3">
|
|
{(() => {
|
|
let parsedDescription: {
|
|
description: string;
|
|
features: Array<{
|
|
icon: string;
|
|
label: string;
|
|
type: "default" | "success" | "destructive";
|
|
}>;
|
|
};
|
|
try {
|
|
parsedDescription = JSON.parse(item.description);
|
|
} catch {
|
|
parsedDescription = { description: "", features: [] };
|
|
}
|
|
|
|
const { description, features } = parsedDescription;
|
|
return (
|
|
<>
|
|
{description && (
|
|
<li className="text-muted-foreground">
|
|
{description}
|
|
</li>
|
|
)}
|
|
{features?.map(
|
|
(
|
|
feature: {
|
|
icon: string;
|
|
label: string;
|
|
type: "default" | "success" | "destructive";
|
|
},
|
|
index: number
|
|
) => (
|
|
<li
|
|
className={cn("flex items-center gap-1", {
|
|
"text-muted-foreground line-through":
|
|
feature.type === "destructive",
|
|
})}
|
|
key={index}
|
|
>
|
|
{feature.icon && (
|
|
<Icon
|
|
className={cn("size-5 text-primary", {
|
|
"text-green-500":
|
|
feature.type === "success",
|
|
"text-destructive":
|
|
feature.type === "destructive",
|
|
})}
|
|
icon={feature.icon}
|
|
/>
|
|
)}
|
|
{feature.label}
|
|
</li>
|
|
)
|
|
)}
|
|
</>
|
|
);
|
|
})()}
|
|
</ul>
|
|
<SubscribeDetail
|
|
subscribe={{
|
|
...item,
|
|
name: undefined,
|
|
}}
|
|
/>
|
|
</CardContent>
|
|
<Separator />
|
|
<CardFooter className="flex flex-col gap-2">
|
|
<h2 className="pb-8 font-semibold text-2xl sm:text-3xl">
|
|
<Display type="currency" value={item.unit_price} />
|
|
<span className="font-medium text-base">
|
|
/
|
|
{unitTimeMap[item.unit_time!] ||
|
|
t(item.unit_time || "Month", item.unit_time || "Month")}
|
|
</span>
|
|
</h2>
|
|
<Button
|
|
className="absolute bottom-0 w-full rounded-t-none rounded-b-xl"
|
|
onClick={() => {
|
|
setSubscribe(item);
|
|
}}
|
|
>
|
|
{t("buy", "Buy")}
|
|
</Button>
|
|
</CardFooter>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
{filteredData?.length === 0 && <Empty />}
|
|
</div>
|
|
<Purchase setSubscribe={setSubscribe} subscribe={subscribe} />
|
|
</>
|
|
);
|
|
}
|