This commit is contained in:
bipproduction
2025-10-21 16:42:08 +08:00
parent 68c35e1257
commit ecfe9c57de

View File

@@ -12,58 +12,78 @@ import {
Badge, Badge,
ScrollArea, ScrollArea,
Tooltip, Tooltip,
Divider,
} from "@mantine/core"; } from "@mantine/core";
import { useLocalStorage, useShallowEffect } from "@mantine/hooks"; import { useLocalStorage, useShallowEffect } from "@mantine/hooks";
import { showNotification } from "@mantine/notifications"; import { showNotification } from "@mantine/notifications";
import { IconRefresh, IconMessageCircle, IconUser, IconCalendar, IconHash, IconCode } from "@tabler/icons-react"; import {
IconRefresh,
IconMessageCircle,
IconUser,
IconCalendar,
IconHash,
IconCode,
} from "@tabler/icons-react";
import dayjs from "dayjs"; import dayjs from "dayjs";
import useSWR from "swr"; import useSWR from "swr";
export default function WaHookHome() { export default function WaHookHome() {
const [page, setPage] = useLocalStorage({ key: "wa-hook-page", defaultValue: 1 }); const [page, setPage] = useLocalStorage({ key: "wa-hook-page", defaultValue: 1 });
const { data, error, isLoading, mutate } = useSWR( const { data, error, isLoading, mutate } = useSWR(
"/wa-hook", `/wa-hook?page=${page}`,
() => apiFetch["wa-hook"].list.get({ query: { page, limit: 10 } }), () => apiFetch["wa-hook"].list.get({ query: { page, limit: 10 } }),
{ {
refreshInterval: 4000, refreshInterval: 4000,
revalidateOnFocus: true, revalidateOnFocus: true,
revalidateOnReconnect: true,
dedupingInterval: 3000, dedupingInterval: 3000,
} }
); );
useShallowEffect(() => { useShallowEffect(() => {
mutate(); mutate();
setPage(data?.data?.list?.length || 1); }, [page]);
}, []);
async function handleReset() { async function handleReset() {
await apiFetch["wa-hook"].reset.post(); await apiFetch["wa-hook"].reset.post();
mutate(); mutate();
showNotification({ showNotification({
title: "Reset Completed", title: "Reset Completed",
message: "WhatsApp Hook data has been successfully reset.", message: "All WhatsApp Hook data has been cleared.",
color: "teal", color: "teal",
}); });
} }
if (isLoading) return <Skeleton height={500} radius="lg" />; if (isLoading) return <Skeleton height={600} radius="lg" />;
if (error) if (error)
return ( return (
<Container p="xl"> <Container p="xl">
<Text c="red.5" ta="center" fz="lg" fw={500}> <Text c="red.5" ta="center" fz="lg" fw={500}>
Failed to load data: {error.message} Failed to load webhook data.
</Text> </Text>
</Container> </Container>
); );
return ( return (
<Container size="lg" p="lg" style={{ backgroundColor: "#191919", borderRadius: 20 }}> <Container
size="lg"
p="xl"
style={{
background: "linear-gradient(145deg, #1a1a1a 0%, #111 100%)",
borderRadius: 24,
border: "1px solid rgba(0,255,200,0.15)",
boxShadow: "0 0 30px rgba(0,255,200,0.1)",
}}
>
<Stack gap="xl"> <Stack gap="xl">
<Group justify="space-between" align="center"> <Group justify="space-between" align="center">
<Title order={2} c="#EAEAEA" fw={700} style={{ letterSpacing: 0.5 }}> <Stack gap={2}>
WhatsApp Hook Monitor <Title order={2} c="#EAEAEA" fw={700} style={{ letterSpacing: 0.5 }}>
</Title> WhatsApp Hook Monitor
</Title>
<Text c="#9A9A9A" fz="sm">
Real-time webhook activity and message tracking
</Text>
</Stack>
<Tooltip label="Reset all webhook data" withArrow color="teal"> <Tooltip label="Reset all webhook data" withArrow color="teal">
<Button <Button
onClick={handleReset} onClick={handleReset}
@@ -71,13 +91,16 @@ export default function WaHookHome() {
variant="gradient" variant="gradient"
gradient={{ from: "#00FFC8", to: "#00FFFF", deg: 45 }} gradient={{ from: "#00FFC8", to: "#00FFFF", deg: 45 }}
radius="xl" radius="xl"
size="md"
> >
Reset Reset Data
</Button> </Button>
</Tooltip> </Tooltip>
</Group> </Group>
<ScrollArea style={{ height: 600 }}> <Divider color="rgba(0,255,200,0.2)" />
<ScrollArea h={600} type="always" scrollHideDelay={0}>
<Stack gap="md"> <Stack gap="md">
{data?.data?.list?.length ? ( {data?.data?.list?.length ? (
data.data.list.map((item) => { data.data.list.map((item) => {
@@ -88,44 +111,55 @@ export default function WaHookHome() {
<Card <Card
key={item.id} key={item.id}
radius="lg" radius="lg"
p="lg"
style={{ style={{
background: background:
"linear-gradient(145deg, rgba(45,45,45,0.8) 0%, rgba(25,25,25,0.95) 100%)", "linear-gradient(160deg, rgba(45,45,45,0.9) 0%, rgba(25,25,25,0.95) 100%)",
backdropFilter: "blur(12px)", backdropFilter: "blur(14px)",
border: "1px solid rgba(0,255,200,0.2)", border: "1px solid rgba(0,255,200,0.25)",
boxShadow: "0 0 10px rgba(0,255,200,0.15)", boxShadow: "0 0 20px rgba(0,255,200,0.1)",
transition: "all 0.2s ease",
}} }}
> >
<Stack gap={6}> <Stack gap={8}>
<Group gap="xs"> <Group gap="xs" align="center">
<IconUser size={16} color="#00FFC8" /> <IconUser size={16} color="#00FFC8" />
<Text c="#EAEAEA" fw={500}> <Text c="#EAEAEA" fw={500}>
{contact?.profile?.name || "Unknown"} {contact?.profile?.name || "Unknown Sender"}
</Text> </Text>
</Group> </Group>
<Group gap="xs"> <Group gap="xs" align="center">
<IconMessageCircle size={16} color="#00FFFF" /> <IconMessageCircle size={16} color="#00FFFF" />
<Text c="#9A9A9A">{msg?.text?.body || "(No message body)"}</Text> <Text c="#9A9A9A" fz="sm">
{msg?.text?.body || "(No message content)"}
</Text>
</Group> </Group>
<Group gap="xs"> <Group gap="xs" align="center">
<IconHash size={16} color="#00FFC8" /> <IconHash size={16} color="#00FFC8" />
<Text c="#9A9A9A" fz="sm"> <Text c="#9A9A9A" fz="xs">
{msg?.id} {msg?.id}
</Text> </Text>
</Group> </Group>
<Group gap="xs"> <Group gap="xs" align="center">
<IconCalendar size={16} color="#00FFFF" /> <IconCalendar size={16} color="#00FFFF" />
<Text c="#9A9A9A" fz="sm"> <Text c="#9A9A9A" fz="xs">
{dayjs(Number(msg?.timestamp) * 1000).format("YYYY-MM-DD HH:mm:ss")} {dayjs(Number(msg?.timestamp) * 1000).format("YYYY-MM-DD HH:mm:ss")}
</Text> </Text>
</Group> </Group>
<Group gap="xs"> <Group gap="xs" align="center">
<IconCode size={16} color="#B554FF" /> <IconCode size={16} color="#B554FF" />
<Badge color="grape" radius="sm" variant="light"> <Badge
color="grape"
radius="sm"
variant="light"
styles={{
root: { backgroundColor: "rgba(181,84,255,0.15)", color: "#EAEAEA" },
}}
>
{msg?.type || "Unknown"} {msg?.type || "Unknown"}
</Badge> </Badge>
</Group> </Group>
@@ -135,13 +169,25 @@ export default function WaHookHome() {
p="sm" p="sm"
radius="md" radius="md"
style={{ style={{
backgroundColor: "#2D2D2D", backgroundColor: "rgba(45,45,45,0.7)",
border: "1px solid rgba(0,255,255,0.1)", border: "1px solid rgba(0,255,255,0.15)",
boxShadow: "inset 0 0 10px rgba(0,255,255,0.1)",
}} }}
> >
<Text c="#EAEAEA" fz="sm"> <Stack gap={4}>
{JSON.stringify(answer, null, 2)} <Text c="#EAEAEA" fw={500} fz="sm">
</Text> Flow Response
</Text>
<Text c="#9A9A9A" fz="xs">
id: {answer.id}
</Text>
<Text c="#9A9A9A" fz="xs">
type: {answer.type}
</Text>
<Text c="#EAEAEA" fz="sm">
{answer.text}
</Text>
</Stack>
</Card> </Card>
)} )}
</Stack> </Stack>
@@ -155,21 +201,21 @@ export default function WaHookHome() {
backgroundColor: "#2D2D2D", backgroundColor: "#2D2D2D",
border: "1px solid rgba(0,255,255,0.1)", border: "1px solid rgba(0,255,255,0.1)",
textAlign: "center", textAlign: "center",
padding: 40, padding: 60,
}} }}
> >
<Text c="#9A9A9A" fz="lg"> <Text c="#9A9A9A" fz="lg">
No webhook data available yet. No webhook activity detected yet.
</Text> </Text>
</Card> </Card>
)} )}
</Stack> </Stack>
</ScrollArea> </ScrollArea>
<Group justify="center" mt="md"> <Group justify="center" mt="xl">
<Pagination <Pagination
value={page} value={page}
total={data?.data?.count || 1} total={Math.ceil((data?.data?.count || 1) / 10)}
onChange={(value) => { onChange={(value) => {
setPage(value); setPage(value);
mutate(); mutate();
@@ -177,6 +223,14 @@ export default function WaHookHome() {
radius="xl" radius="xl"
withEdges withEdges
color="teal" color="teal"
size="md"
styles={{
control: {
backgroundColor: "#2D2D2D",
border: "1px solid rgba(0,255,200,0.15)",
color: "#EAEAEA",
},
}}
/> />
</Group> </Group>
</Stack> </Stack>