inspiren-sem-tool/resources/js/forms/activities/activityForm.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

228 lines
9.9 KiB
TypeScript

import { dateInputFormat, datetimeParse } from "@/utils/datetime";
import { FormStatus, ProjectActivity } from "@/types";
import { useForm } from "@inertiajs/react";
import { ActionIcon, Button, FileInput, Flex, Grid, Group, HoverCard, NumberInput, Paper, Radio, Select, SelectItem, SimpleGrid, Stack, Switch, Tabs, Text, TextInput, Textarea, Tooltip, rem } from "@mantine/core";
import { DatePickerInput } from "@mantine/dates";
import { useForm as useMantineForm } from "@mantine/form";
import { IconArrowIteration, IconDeviceFloppy, IconInfoCircle, IconListDetails, IconPlus, IconSeo, IconTimelineEventText, IconTrash, IconUserCheck } from "@tabler/icons-react";
import dayjs from "dayjs";
import { useEffect } from "react";
import { RichTextEditor } from '@mantine/tiptap';
import { useEditor } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import Link from '@tiptap/extension-link';
interface Props {
activity?: ProjectActivity;
activityCategories?: any[];
status?: FormStatus;
projectId: number;
unassignedTickets?: any[];
formAction?: string;
formMethod?: 'post' | 'patch';
onSuccess?: () => void;
};
export default function ActivityForm({ activity, activityCategories, status, projectId, unassignedTickets,formAction, formMethod, onSuccess }: Props) {
// const activityCategoryOptions: SelectItem[] = activityCategories?.map((category) => ({
// label: category,
// value: category,
// }));
const ticketOptions: SelectItem[] = Object.entries(unassignedTickets).map(
([key, value], index) => ({
label: value,
value: key.toString(),
})
);
const { data, setData, post, patch, processing, errors, ...form } = useForm<{
task_description: string;
category: string | null;
estimated_completed_at: string | null;
activity_type: string;
// ticket_id: string | null;
notification_status: boolean;
}>({
task_description: activity?.task_description ?? '',
category: activity?.activity_type ?? null,
estimated_completed_at: activity?.estimated_completed_at ?? null,
activity_type: (!activity?.estimated_completed_at && !activity?.completed_at) ? 'report' : (activity?.estimated_completed_at && !activity?.completed_at) ? 'scheduled' : 'report',
// ticket_id: activity?.assignation?.ticket_id?.toString() ?? null,
notification_status: activity?.notification_status ?? false,
});
const editor = useEditor({
extensions: [StarterKit.configure({
bulletList: false,
orderedList: false,
}), Link],
content: activity?.task_description || '',
onUpdate({ editor }) {
setData('task_description', editor.getHTML());
},
});
useEffect(() => {
setData('task_description', activity?.task_description ?? '');
setData('category', activity?.activity_type ?? null);
setData('estimated_completed_at', activity?.estimated_completed_at ?? null);
setData('activity_type', (!activity?.estimated_completed_at && !activity?.completed_at) ? 'report' : (activity?.estimated_completed_at && !activity?.completed_at) ? 'scheduled' : 'report');
setData('notification_status', activity?.notification_status ?? false);
if (editor) {
editor.commands.setContent(activity?.task_description ?? '');
}
}, [activity, setData, editor]);
const handleSubmit = (e) => {
e.preventDefault();
const formStatus: FormStatus = status ?? 'create';
const actionUrl =
formAction ??
route('google-ads.accounts.activity.storeActivity', { id: projectId });
const method = formMethod ?? (formStatus === 'update' ? 'patch' : 'post');
const options = {
preserveScroll: true,
onSuccess: () => {
onSuccess?.();
},
};
if (method === 'patch') {
patch(actionUrl, { ...options, data });
return;
}
post(actionUrl, options);
//else if (status === 'update') {
// post(route('admin.project.activity.update', { id: activity?.id }), data);
// }
};
return (
<Grid>
<Grid.Col
md={12}
lg={12}
>
<form onSubmit={handleSubmit}>
<Stack>
<Stack>
<Radio.Group
name="activityType"
label="Activity Type"
value={data.activity_type}
onChange={(value) => setData("activity_type", value)}
withAsterisk
>
<Group mt="xs">
<Radio value="report" label="Report" />
<Radio value="scheduled" label="Scheduled" />
{/* <Radio value="customer_notes" label="Customer Notes" /> */}
</Group>
</Radio.Group>
{/* {data.activity_type != 'customer_notes' ? (
<Select
label={'Category'}
placeholder="Select One..."
data={activityCategoryOptions}
value={data.category}
onChange={(value) => setData('category', value ? value : '')}
error={errors.category}
required
searchable
clearable
/>
) : null} */}
<TextInput
placeholder="Insert Category"
label="Category"
required
withAsterisk
value={data.category ?? ''}
onChange={(event) => setData("category", event.target.value)}
error={errors.category}
/>
{data.activity_type == 'scheduled' ? (
<DatePickerInput
label={'Estimated Completion Date'}
// @ts-ignore
placeholder="Select a Date..."
valueFormat={dateInputFormat}
value={data.estimated_completed_at ? dayjs(data.estimated_completed_at).toDate() : null}
onChange={(value) => setData('estimated_completed_at', value ? dayjs(value).format(datetimeParse) : '')}
error={errors.estimated_completed_at}
required
/>
) : null}
<div>
<Text fw={500} mb={4}>
Description <Text span c="red">*</Text>
</Text>
<RichTextEditor editor={editor}>
<RichTextEditor.Toolbar sticky stickyOffset={60}>
<RichTextEditor.ControlsGroup>
<RichTextEditor.Bold />
<RichTextEditor.Italic />
<RichTextEditor.Link />
<RichTextEditor.Unlink />
</RichTextEditor.ControlsGroup>
</RichTextEditor.Toolbar>
<RichTextEditor.Content
style={{ minHeight: 300 }} // 👈 increase this
/>
</RichTextEditor>
{errors.description && (
<Text c="red" size="sm" mt={4}>
{errors.description}
</Text>
)}
</div>
{/* {data.activity_type != 'customer_notes' ? (
<Select
label={'Ticket Linkage'}
placeholder="Select One..."
data={ticketOptions}
value={data.ticket_id}
onChange={(value) => setData('ticket_id', value ? value : '')}
error={errors.ticket_id}
searchable
clearable
/>
) : null} */}
{/* <Switch
label={'Email Customer on Project Updates'}
checked={data.notification_status}
onChange={(e) => setData('notification_status', e.target.checked)}
error={errors.notification_status}
/> */}
</Stack>
<Button
type="submit"
leftIcon={(<IconDeviceFloppy />)}
disabled={processing}
>
Submit
</Button>
</Stack>
</form>
</Grid.Col>
</Grid>
)
}