diff --git a/src/mission-control-client/src/components/MissionsTable/MissionsTable.tsx b/src/mission-control-client/src/components/MissionsTable/MissionsTable.tsx new file mode 100644 index 0000000..4e2bb93 --- /dev/null +++ b/src/mission-control-client/src/components/MissionsTable/MissionsTable.tsx @@ -0,0 +1,192 @@ +import { Loader, Alert, Table, ActionIcon, Popover, Button, Text, Group, Paper, Select, Stack } from "@mantine/core"; +import { IconChevronDown, IconChevronRight } from "@tabler/icons-react"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { useState } from "react"; +import { listMissions, type Mission } from "../../api/missions"; +import { toReadableDateTime } from "../../utils/dateUtils"; +import { MissionLaunchStatusBadge } from "../MissionLaunchStatusBadge"; +import { MissionStatusBadge } from "../MissionStatusBadge"; +import { DateTimePicker } from "@mantine/dates"; +import { useForm } from "@mantine/form"; +import { notifications } from "@mantine/notifications"; +import { createMissionLaunch, type MissionLaunchStatus, MissionLaunchStatuses } from "../../api/missionLaunches"; + +export function MissionsTable() { + const missionsQuery = useQuery({ + queryKey: ['missions'], + queryFn: listMissions, + }); + + if (missionsQuery.isPending) { + return ; + } + + if (missionsQuery.isError) { + return ( + + Is the API running? + + ); + } + + return ( + + + + + Name + Description + Status + + + + {missionsQuery.data.map((mission) => ( + + ))} + +
+ ); +} + +function MissionsTableRow({ mission }: { mission: Mission }) { + const [expanded, setExpanded] = useState(false); + + return ( + <> + + + setExpanded((expanded) => !expanded)}> + {expanded ? : } + + + {mission.name} + + + {mission.description} + + + + + + + {expanded === true ? ( + <> + + +

+ Launches +

+ + + + Scheduled For + Status + + + + {mission.missionLaunches.map((missionLaunch) => ( + + {toReadableDateTime(missionLaunch.scheduledFor)} + + + + + ))} + +
+
+
+ + + + + + + + + + + + + + ) : null} + + ); +} + +function CreateMissionLaunchForm({ missionId }: { missionId: string }) { + const queryClient = useQueryClient(); + + const form = useForm({ + mode: 'uncontrolled', + initialValues: { scheduledFor: '', status: '' }, + validate: { + scheduledFor: (value) => + value.length === 0 ? 'Scheduled For is required' : null, + status: (value) => + value.trim().length === 0 ? 'Status is required' : null, + }, + }); + + const createMissionLaunchMutation = useMutation({ + mutationFn: createMissionLaunch, + onSuccess: () => { + notifications.show({ + title: 'Mission launch created', + message: `Mission Launch created!`, + color: 'green', + }); + form.reset(); + return queryClient.invalidateQueries({ queryKey: ['missions'] }); + }, + onError: () => + notifications.show({ + title: 'Something went wrong', + message: 'The mission launch could not be created.', + color: 'red', + }), + }); + + return ( + +
+ createMissionLaunchMutation.mutate({ + missionId, + scheduledFor: new Date(values.scheduledFor).toISOString(), + status: values.status as MissionLaunchStatus, + }), + )} + > + + + + + + + +
+
+ ); +} diff --git a/src/mission-control-client/src/routes/missions.tsx b/src/mission-control-client/src/routes/missions.tsx index 9c7325b..8e9b995 100644 --- a/src/mission-control-client/src/routes/missions.tsx +++ b/src/mission-control-client/src/routes/missions.tsx @@ -1,35 +1,18 @@ import { - ActionIcon, - Alert, Button, Group, - Loader, Paper, - Popover, - Select, Stack, - Table, - Text, Textarea, TextInput, Title, } from '@mantine/core'; -import { DateTimePicker } from '@mantine/dates'; import { useForm } from '@mantine/form'; import { notifications } from '@mantine/notifications'; -import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { useMutation, useQueryClient } from '@tanstack/react-query'; import { createFileRoute } from '@tanstack/react-router'; -import { useState } from 'react'; -import { - createMissionLaunch, - MissionLaunchStatuses, - type MissionLaunchStatus, -} from '../api/missionLaunches'; -import { createMission, listMissions, type Mission } from '../api/missions'; -import { MissionLaunchStatusBadge } from '../components/MissionLaunchStatusBadge'; -import { MissionStatusBadge } from '../components/MissionStatusBadge'; -import { IconChevronDown, IconChevronRight } from '@tabler/icons-react'; -import { toReadableDateTime } from '../utils/dateUtils'; +import { createMission } from '../api/missions'; +import { MissionsTable } from '../components/MissionsTable/MissionsTable'; export const Route = createFileRoute('/missions')({ component: MissionsPage, @@ -108,184 +91,4 @@ function CreateMissionForm() { ); -} - -function CreateMissionLaunchForm({ missionId }: { missionId: string }) { - const queryClient = useQueryClient(); - - const form = useForm({ - mode: 'uncontrolled', - initialValues: { scheduledFor: '', status: '' }, - validate: { - scheduledFor: (value) => - value.length === 0 ? 'Scheduled For is required' : null, - status: (value) => - value.trim().length === 0 ? 'Status is required' : null, - }, - }); - - const createMissionLaunchMutation = useMutation({ - mutationFn: createMissionLaunch, - onSuccess: () => { - notifications.show({ - title: 'Mission launch created', - message: `Mission Launch created!`, - color: 'green', - }); - form.reset(); - return queryClient.invalidateQueries({ queryKey: ['missions'] }); - }, - onError: () => - notifications.show({ - title: 'Something went wrong', - message: 'The mission launch could not be created.', - color: 'red', - }), - }); - - return ( - -
- createMissionLaunchMutation.mutate({ - missionId, - scheduledFor: new Date(values.scheduledFor).toISOString(), - status: values.status as MissionLaunchStatus, - }), - )} - > - - - - - - - -
-
- ); -} - -function MissionsTable() { - const missionsQuery = useQuery({ - queryKey: ['missions'], - queryFn: listMissions, - }); - - if (missionsQuery.isPending) { - return ; - } - - if (missionsQuery.isError) { - return ( - - Is the API running? - - ); - } - - return ( - - - - - Name - Description - Status - - - - {missionsQuery.data.map((mission) => ( - - ))} - -
- ); -} - -function MissionsTableRow({ mission }: { mission: Mission }) { - const [expanded, setExpanded] = useState(false); - - return ( - <> - - - setExpanded((expanded) => !expanded)}> - {expanded ? : } - - - {mission.name} - - - {mission.description} - - - - - - - {expanded === true ? ( - <> - - -

- Launches -

- - - - Scheduled For - Status - - - - {mission.missionLaunches.map((missionLaunch) => ( - - {toReadableDateTime(missionLaunch.scheduledFor)} - - - - - ))} - -
-
-
- - - - - - - - - - - - - - ) : null} - - ); -} +} \ No newline at end of file