inspiren-sem-tool/resources/js/pages/campaigns/index.tsx
brian-inspiren 221d3f8173
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
feat: sem codebase
2026-05-21 11:28:03 +08:00

154 lines
4.7 KiB
TypeScript

import React, { useMemo } from 'react';
import AppLayout from '../../layouts/app-layout';
import {
Container,
Title,
Group,
Button,
Badge,
ActionIcon,
Stack,
Text,
} from '@mantine/core';
import { IconEye, IconRefresh } from '@tabler/icons-react';
import { MantineReactTable } from 'mantine-react-table';
import type { MRT_Row } from 'mantine-react-table';
import { Link, router } from '@inertiajs/react';
import { Client } from "@/types";
interface Props {
clients: Client[];
googleCompanySyncRunning: boolean;
}
const currencyFormatter = new Intl.NumberFormat('en-MY', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
const parseAmount = (value?: number | string | null): number => {
if (value === undefined || value === null) {
return 0;
}
const normalized = typeof value === 'string' ? Number(value.replace(/,/g, '')) : Number(value);
return Number.isNaN(normalized) ? 0 : normalized;
};
export default function TicketDetails({
clients,
googleCompanySyncRunning,
}: Props) {
const [syncing, setSyncing] = React.useState(false);
// console.log(clients);
const campaignsData = clients ?? [];
const columns = useMemo(
() => [
{
accessorKey: 'customer_id',
header: 'Google ID',
},
{
accessorKey: 'sql_acc_code',
header: 'Customer Code',
},
{
accessorKey: 'name',
header: 'Google Account Name',
},
{
accessorKey: 'status',
header: 'Status',
Cell: ({ cell }: any) => {
const value = cell.getValue() as string;
const color =
value === 'ENABLED'
? 'green'
: value === 'PAUSED'
? 'yellow'
: value === 'ENDED'
? 'red'
: 'gray';
return <Badge color={color}>{value}</Badge>;
},
},
{
accessorKey: 'industry',
header: 'Industry',
},
{
accessorKey: 'assigned_person',
header: 'Assigned Person',
Cell: ({ cell }: any) => cell.getValue() ?? '—',
},
{
accessorKey: 'sales_person',
header: 'Sales Person',
Cell: ({ cell }: any) => cell.getValue() ?? '—',
},
],
[]
);
const renderRowActions = ({ row }: { row: MRT_Row<Client> }) => {
const client = row.original;
return (
<Group spacing="xs">
<ActionIcon
color="blue"
component={Link}
href={`/google-ads/accounts/${client.customer_id}`}
>
<IconEye size={18} />
</ActionIcon>
</Group>
);
};
const syncGoogleRecords = () => {
if (syncing || googleCompanySyncRunning) {
return;
}
setSyncing(true);
router.post(
route("google-ads.accounts.sync-google-company-details"),
{},
{
preserveScroll: true,
onFinish: () => setSyncing(false),
},
);
};
return (
<AppLayout>
<Container size="xl" px="xs">
<Group position="apart" mb="md">
<Stack spacing={2}>
<Title order={2}>Clients</Title>
<Text size="sm" color="dimmed">
Sync Google account records before linking pending invoices to new clients.
</Text>
</Stack>
<Button
leftIcon={<IconRefresh size={16} />}
onClick={syncGoogleRecords}
loading={syncing}
disabled={googleCompanySyncRunning}
>
{googleCompanySyncRunning ? "Sync running" : "Sync Google records"}
</Button>
</Group>
<MantineReactTable
columns={columns}
data={clients}
enableRowActions // REQUIRED
positionActionsColumn="last" // optional but recommended
renderRowActions={renderRowActions}
/>
</Container>
</AppLayout>
);
}