25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 

160 satır
5.0 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 Typography from "@mui/material/Typography";
  6. import { useTranslation } from "react-i18next";
  7. import TransferList from "../TransferList";
  8. import Button from "@mui/material/Button";
  9. import React, { useCallback, useMemo, useState } from "react";
  10. import CardActions from "@mui/material/CardActions";
  11. import RestartAlt from "@mui/icons-material/RestartAlt";
  12. import FormControl from "@mui/material/FormControl";
  13. import Select, { SelectChangeEvent } from "@mui/material/Select";
  14. import MenuItem from "@mui/material/MenuItem";
  15. import InputLabel from "@mui/material/InputLabel";
  16. import { Task, TaskTemplate } from "@/app/api/tasks";
  17. import { useFormContext } from "react-hook-form";
  18. import { CreateProjectInputs } from "@/app/api/projects/actions";
  19. import isNumber from "lodash/isNumber";
  20. import intersectionWith from "lodash/intersectionWith";
  21. interface Props {
  22. allTasks: Task[];
  23. taskTemplates: TaskTemplate[];
  24. isActive: boolean;
  25. }
  26. const TaskSetup: React.FC<Props> = ({
  27. allTasks: tasks,
  28. taskTemplates,
  29. isActive,
  30. }) => {
  31. const { t } = useTranslation();
  32. const { setValue, watch } = useFormContext<CreateProjectInputs>();
  33. const currentTaskGroups = watch("taskGroups");
  34. const currentTaskIds = Object.values(currentTaskGroups).reduce<Task["id"][]>(
  35. (acc, group) => {
  36. return [...acc, ...group.taskIds];
  37. },
  38. [],
  39. );
  40. const onReset = useCallback(() => {
  41. setValue("taskGroups", {});
  42. }, [setValue]);
  43. const [selectedTaskTemplateId, setSelectedTaskTemplateId] = useState<
  44. "All" | number
  45. >("All");
  46. const onSelectTaskTemplate = useCallback(
  47. (e: SelectChangeEvent<number | "All">) => {
  48. if (e.target.value === "All" || isNumber(e.target.value)) {
  49. setSelectedTaskTemplateId(e.target.value);
  50. // onReset();
  51. }
  52. },
  53. [onReset],
  54. );
  55. const items = useMemo(() => {
  56. const taskList =
  57. selectedTaskTemplateId === "All"
  58. ? tasks
  59. : taskTemplates.find(
  60. (template) => template.id === selectedTaskTemplateId,
  61. )?.tasks || tasks;
  62. return taskList.map((t) => ({
  63. id: t.id,
  64. label: t.name,
  65. group: t.taskGroup,
  66. }));
  67. }, [tasks, selectedTaskTemplateId, taskTemplates]);
  68. const selectedItems = useMemo(() => {
  69. return intersectionWith(
  70. tasks,
  71. currentTaskIds,
  72. (task, taskId) => task.id === taskId,
  73. ).map((t) => ({ id: t.id, label: t.name, group: t.taskGroup }));
  74. }, [currentTaskIds, tasks]);
  75. return (
  76. <Card sx={{ display: isActive ? "block" : "none" }}>
  77. <CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
  78. <Typography variant="overline" display="block" marginBlockEnd={1}>
  79. {t("Task List Setup")}
  80. </Typography>
  81. <Grid
  82. container
  83. spacing={2}
  84. columns={{ xs: 6, sm: 12 }}
  85. marginBlockEnd={1}
  86. >
  87. <Grid item xs={6}>
  88. <FormControl fullWidth>
  89. <InputLabel>{t("Task List Source")}</InputLabel>
  90. <Select<"All" | number>
  91. label={t("Task List Source")}
  92. value={selectedTaskTemplateId}
  93. onChange={onSelectTaskTemplate}
  94. >
  95. <MenuItem value={"All"}>{t("All tasks")}</MenuItem>
  96. {taskTemplates.map((template, index) => (
  97. <MenuItem key={`${template.id}-${index}`} value={template.id}>
  98. {template.name}
  99. </MenuItem>
  100. ))}
  101. </Select>
  102. </FormControl>
  103. </Grid>
  104. </Grid>
  105. <TransferList
  106. allItems={items}
  107. selectedItems={selectedItems}
  108. onChange={(selectedTasks) => {
  109. const newTaskGroups = selectedTasks.reduce<
  110. CreateProjectInputs["taskGroups"]
  111. >((acc, item) => {
  112. if (!item.group) {
  113. // TODO: this should not happen (all tasks are part of a group)
  114. return acc;
  115. }
  116. if (!acc[item.group.id]) {
  117. return {
  118. ...acc,
  119. [item.group.id]: {
  120. taskIds: [item.id],
  121. percentAllocation:
  122. currentTaskGroups[item.group.id]?.percentAllocation || 0,
  123. },
  124. };
  125. }
  126. return {
  127. ...acc,
  128. [item.group.id]: {
  129. ...acc[item.group.id],
  130. taskIds: [...acc[item.group.id].taskIds, item.id],
  131. },
  132. };
  133. }, {});
  134. setValue("taskGroups", newTaskGroups);
  135. }}
  136. allItemsLabel={t("Task Pool")}
  137. selectedItemsLabel={t("Project Task List")}
  138. />
  139. <CardActions sx={{ justifyContent: "flex-end" }}>
  140. <Button variant="text" startIcon={<RestartAlt />} onClick={onReset}>
  141. {t("Reset")}
  142. </Button>
  143. </CardActions>
  144. </CardContent>
  145. </Card>
  146. );
  147. };
  148. export default TaskSetup;