Skip to content

Commit ab286c9

Browse files
committed
feat: update done ratio
- added update done ratio feature - fixed invalidate queries - fixed empty additional issues query
1 parent 2479f43 commit ab286c9

File tree

5 files changed

+44
-2
lines changed

5 files changed

+44
-2
lines changed

src/api/redmine.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ export const createTimeEntry = async (entry: TCreateTimeEntry) => {
2121
.then((res) => res.data);
2222
};
2323

24+
export const updateIssue = async (id: number, issue: Partial<Omit<TIssue, "id">>) => {
25+
return instance
26+
.put(`/issues/${id}.json`, {
27+
issue: issue,
28+
})
29+
.then((res) => res.data);
30+
};
31+
2432
export const getTimeEntryActivities = async (): Promise<TTimeEntryActivity[]> => {
2533
return instance.get("/enumerations/time_entry_activities.json").then((res) => res.data.time_entry_activities);
2634
};

src/components/issues/CreateTimeEntryModal.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
22
import { AxiosError, isAxiosError } from "axios";
33
import clsx from "clsx";
44
import { Field, Form, Formik, FormikProps } from "formik";
5-
import { useEffect, useRef } from "react";
5+
import { useEffect, useRef, useState } from "react";
66
import * as Yup from "yup";
7-
import { createTimeEntry, getTimeEntryActivities } from "../../api/redmine";
7+
import { createTimeEntry, getTimeEntryActivities, updateIssue } from "../../api/redmine";
88
import useSettings from "../../hooks/useSettings";
99
import { TCreateTimeEntry, TIssue, TRedmineError } from "../../types/redmine";
1010
import InputField from "../general/InputField";
1111
import Modal from "../general/Modal";
1212
import SelectField from "../general/SelectField";
1313
import Toast from "../general/Toast";
14+
import DoneSlider from "./DoneSlider";
1415

1516
type PropTypes = {
1617
issue: TIssue;
@@ -38,10 +39,16 @@ const CreateTimeEntryModal = ({ issue, time, onClose, onSuccess }: PropTypes) =>
3839
mutationFn: (entry: TCreateTimeEntry) => createTimeEntry(entry),
3940
onSuccess: () => {
4041
queryClient.invalidateQueries(["issues"]);
42+
queryClient.invalidateQueries(["additionalIssues"]);
4143
onSuccess();
4244
},
4345
});
4446

47+
const [doneRatio, setDoneRatio] = useState(issue.done_ratio);
48+
const updateIssueMutation = useMutation({
49+
mutationFn: (data: { done_ratio: number }) => updateIssue(issue.id, data),
50+
});
51+
4552
return (
4653
<>
4754
<Modal title="Add time spent" onClose={onClose}>
@@ -59,6 +66,9 @@ const CreateTimeEntryModal = ({ issue, time, onClose, onSuccess }: PropTypes) =>
5966
})}
6067
onSubmit={async (values, { setSubmitting }) => {
6168
//console.log("onSubmit", values);
69+
if (issue.done_ratio !== doneRatio) {
70+
await updateIssueMutation.mutateAsync({ done_ratio: doneRatio });
71+
}
6272
await createTimeEntryMutation.mutateAsync(values);
6373
setSubmitting(false);
6474
}}
@@ -73,6 +83,7 @@ const CreateTimeEntryModal = ({ issue, time, onClose, onSuccess }: PropTypes) =>
7383
</a>{" "}
7484
{issue.subject}
7585
</h1>
86+
<DoneSlider name="done_ratio" value={doneRatio} onChange={(e) => setDoneRatio(e.target.valueAsNumber)} className="mb-1" />
7687
<Field type="number" name="hours" title="Hours" placeholder="Hours" min="0" step="0.01" required as={InputField} size="sm" error={touched.hours && errors.hours} autoComplete="off" />
7788
<Field type="text" name="comments" title="Comments" placeholder="Comments" as={InputField} size="sm" error={touched.comments && errors.comments} autoFocus />
7889
<Field type="select" name="activity_id" title="Activity" placeholder="Activity" required as={SelectField} size="sm" error={touched.activity_id && errors.activity_id}>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import clsx from "clsx";
2+
3+
interface PropTypes extends Omit<React.ComponentProps<"input">, "value"> {
4+
value: number;
5+
}
6+
const DoneSlider = ({ value, className, ...props }: PropTypes) => {
7+
return (
8+
<div className={clsx("relative", className)}>
9+
<input {...props} value={value} min="0" max="100" step="10" type="range" className="transparent h-5 appearance-none border-transparent w-[80px]" style={{ background: `linear-gradient(90deg, #bae0ba ${value}%, #eeeeee ${value}%)` }} />
10+
<p className="absolute top-1 left-1 text-xs font-medium text-gray-600 leading-none select-none">{value}%</p>
11+
</div>
12+
);
13+
};
14+
15+
export default DoneSlider;

src/hooks/useMyIssues.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const useMyIssues = (additionalIssuesIds: number[], search: string) => {
2121
queryKey: ["additionalIssues", additionalIssuesIds],
2222
queryFn: ({ pageParam = 0 }) => getOpenIssues(additionalIssuesIds, pageParam * 100, 100),
2323
getNextPageParam: (lastPage, allPages) => (lastPage.length === 100 ? allPages.length : undefined),
24+
enabled: additionalIssuesIds.length > 0,
2425
});
2526

2627
// auto fetch all pages

src/index.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,10 @@
1717
background-color: #1e3a8a;
1818
border-radius: 3px;
1919
}
20+
21+
input[name="done_ratio"]::-webkit-slider-thumb {
22+
-webkit-appearance: none;
23+
appearance: none;
24+
cursor: pointer;
25+
width: 2px;
26+
}

0 commit comments

Comments
 (0)