You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

138 lines
3.9 KiB

  1. "use client";
  2. import Card from "@mui/material/Card";
  3. import CardContent from "@mui/material/CardContent";
  4. import Grid from "@mui/material/Grid";
  5. import TextField from "@mui/material/TextField";
  6. import Typography from "@mui/material/Typography";
  7. import { useTranslation } from "react-i18next";
  8. import TransferList from "../TransferList";
  9. import Button from "@mui/material/Button";
  10. import Check from "@mui/icons-material/Check";
  11. import Close from "@mui/icons-material/Close";
  12. import { useRouter } from "next/navigation";
  13. import React from "react";
  14. import Stack from "@mui/material/Stack";
  15. import { Task } from "@/app/api/tasks";
  16. import {
  17. NewTaskTemplateFormInputs,
  18. saveTaskTemplate,
  19. } from "@/app/api/tasks/actions";
  20. import { SubmitHandler, useForm } from "react-hook-form";
  21. interface Props {
  22. tasks: Task[];
  23. }
  24. const CreateTaskTemplate: React.FC<Props> = ({ tasks }) => {
  25. const { t } = useTranslation();
  26. const router = useRouter();
  27. const handleCancel = () => {
  28. router.back();
  29. };
  30. const items = React.useMemo(
  31. () =>
  32. tasks.map((task) => ({
  33. id: task.id,
  34. label: task.name,
  35. group: task.taskGroup || undefined,
  36. })),
  37. [tasks],
  38. );
  39. const [serverError, setServerError] = React.useState("");
  40. const {
  41. register,
  42. handleSubmit,
  43. setValue,
  44. formState: { errors, isSubmitting },
  45. } = useForm<NewTaskTemplateFormInputs>();
  46. const onSubmit: SubmitHandler<NewTaskTemplateFormInputs> = React.useCallback(
  47. async (data) => {
  48. try {
  49. setServerError("");
  50. await saveTaskTemplate(data);
  51. router.replace("/tasks");
  52. } catch (e) {
  53. setServerError(t("An error has occurred. Please try again later."));
  54. }
  55. },
  56. [router, t],
  57. );
  58. return (
  59. <Stack component="form" onSubmit={handleSubmit(onSubmit)} gap={2}>
  60. <Card>
  61. <CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
  62. <Typography variant="overline">{t("Task List Setup")}</Typography>
  63. <Grid
  64. container
  65. spacing={2}
  66. columns={{ xs: 6, sm: 12 }}
  67. marginBlockEnd={1}
  68. >
  69. <Grid item xs={6}>
  70. <TextField
  71. label={t("Task Template Code")}
  72. fullWidth
  73. {...register("code", {
  74. required: t("Task template code is required"),
  75. })}
  76. error={Boolean(errors.code?.message)}
  77. helperText={errors.code?.message}
  78. />
  79. </Grid>
  80. <Grid item xs={6}>
  81. <TextField
  82. label={t("Task Template Name")}
  83. fullWidth
  84. {...register("name", {
  85. required: t("Task template name is required"),
  86. })}
  87. error={Boolean(errors.name?.message)}
  88. helperText={errors.name?.message}
  89. />
  90. </Grid>
  91. </Grid>
  92. <TransferList
  93. allItems={items}
  94. initiallySelectedItems={[]}
  95. onChange={(selectedItems) => {
  96. setValue(
  97. "taskIds",
  98. selectedItems.map((item) => item.id),
  99. );
  100. }}
  101. allItemsLabel={t("Task Pool")}
  102. selectedItemsLabel={t("Task List Template")}
  103. />
  104. </CardContent>
  105. </Card>
  106. {serverError && (
  107. <Typography variant="body2" color="error" alignSelf="flex-end">
  108. {serverError}
  109. </Typography>
  110. )}
  111. <Stack direction="row" justifyContent="flex-end" gap={1}>
  112. <Button variant="outlined" startIcon={<Close />} onClick={handleCancel}>
  113. {t("Cancel")}
  114. </Button>
  115. <Button
  116. variant="contained"
  117. startIcon={<Check />}
  118. type="submit"
  119. disabled={isSubmitting}
  120. >
  121. {t("Confirm")}
  122. </Button>
  123. </Stack>
  124. </Stack>
  125. );
  126. };
  127. export default CreateTaskTemplate;