Skip to content

Commit cdd507d

Browse files
committed
feat: Added search issues by project
- Added search mode (issue/project) - Fixed focus color - Improved input field types - Added component Switch - Added component Toggle
1 parent ebe5fd2 commit cdd507d

File tree

13 files changed

+225
-50
lines changed

13 files changed

+225
-50
lines changed

src/api/redmine.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,22 @@ export const getAllMyOpenIssues = async (offset = 0, limit = 100): Promise<TIssu
1111
return instance.get(`/issues.json?offset=${offset}&limit=${limit}&status_id=open&assigned_to_id=me&sort=updated_on:desc`).then((res) => res.data.issues);
1212
};
1313

14-
export const getOpenIssues = async (ids: number[], offset = 0, limit = 100): Promise<TIssue[]> => {
14+
export const getOpenIssuesByIds = async (ids: number[], offset = 0, limit = 100): Promise<TIssue[]> => {
1515
return instance.get(`/issues.json?offset=${offset}&limit=${limit}&status_id=open&issue_id=${ids.join(",")}&sort=updated_on:desc`).then((res) => res.data.issues);
1616
};
1717

18+
export const getOpenIssuesByProject = async (projectId: number, offset = 0, limit = 100): Promise<TIssue[]> => {
19+
return instance.get(`/issues.json?offset=${offset}&limit=${limit}&status_id=open&project_id=${projectId}&sort=updated_on:desc`).then((res) => res.data.issues);
20+
};
21+
1822
export const searchOpenIssues = async (query: string): Promise<TSearchResult[]> => {
1923
return instance.get(`/search.json?q=${query}&scope=my_project&titles_only=1&issues=1&open_issues=1`).then((res) => res.data.results);
2024
};
2125

26+
export const searchProjects = async (query: string): Promise<TSearchResult[]> => {
27+
return instance.get(`/search.json?q=${query}&scope=my_project&titles_only=1&projects=1`).then((res) => res.data.results);
28+
};
29+
2230
export const updateIssue = async (id: number, issue: Partial<Omit<TIssue, "id">>) => {
2331
return instance
2432
.put(`/issues/${id}.json`, {

src/components/general/CheckBox.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import clsx from "clsx";
22
import { useId } from "react";
33

4-
interface PropTypes extends React.ComponentProps<"input"> {
4+
interface PropTypes extends Omit<React.ComponentProps<"input">, "id" | "type"> {
55
title: string;
66
description?: string;
77
}
@@ -18,7 +18,7 @@ const CheckBox = ({ title, description, ...props }: PropTypes) => {
1818
type="checkbox"
1919
className={clsx(
2020
"w-4 h-4 accent-primary-600 bg-gray-100 border-gray-300 rounded dark:ring-offset-gray-800 dark:bg-gray-700 dark:border-gray-600",
21-
"focus:ring-2 focus:ring-primary-300 focus:outline-none dark:focus:ring-primary-600",
21+
"focus:ring-2 focus:ring-primary-300 focus:outline-none dark:focus:ring-primary-800",
2222
props.className
2323
)}
2424
/>

src/components/general/DateField.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,27 @@ import Flatpickr, { DateTimePickerProps } from "react-flatpickr";
77
import "../../assets/themes/dark.css";
88
import "../../assets/themes/light.css";
99

10-
interface PropTypes extends Omit<DateTimePickerProps, "size" | "onChange"> {
10+
interface PropTypes extends Omit<DateTimePickerProps, "id" | "size" | "onChange"> {
1111
size?: "sm" | "md";
1212
icon?: React.ReactNode;
1313
error?: string;
1414
onChange?: ChangeEventHandler<HTMLInputElement>;
1515
}
1616

17-
const DateField = ({ size = "md", icon, error, className, value, onChange, onBlur, ...props }: PropTypes) => {
17+
const DateField = ({ size = "md", title, icon, error, className, value, onChange, onBlur, ...props }: PropTypes) => {
1818
const id = useId();
1919

2020
return (
2121
<div>
22-
{props.title && (
22+
{title && (
2323
<label
2424
htmlFor={id}
2525
className={clsx("block font-medium text-gray-900 dark:text-white mb-1", {
2626
"text-xs": size === "sm",
2727
"text-sm": size === "md",
2828
})}
2929
>
30-
{props.title}
30+
{title}
3131
{props.required && <FontAwesomeIcon icon={faAsterisk} size="2xs" className="text-red-600 ml-1" />}
3232
</label>
3333
)}
@@ -55,7 +55,7 @@ const DateField = ({ size = "md", icon, error, className, value, onChange, onBlu
5555
className={clsx(
5656
"text-sm rounded-lg block w-full",
5757
"bg-gray-50 border border-gray-300 text-gray-900 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white",
58-
"focus:ring-2 focus:ring-primary-300 focus:outline-none dark:focus:ring-primary-600",
58+
"focus:ring-2 focus:ring-primary-300 focus:outline-none dark:focus:ring-primary-800",
5959
{
6060
"border-red-500 text-red-900 placeholder-red-700 dark:text-red-500 dark:placeholder-red-500 dark:border-red-500": error !== undefined,
6161
"pl-8": !!icon,

src/components/general/InputField.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,27 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
33
import clsx from "clsx";
44
import { forwardRef, useId } from "react";
55

6-
interface PropTypes extends Omit<React.ComponentProps<"input">, "size"> {
6+
interface PropTypes extends Omit<React.ComponentProps<"input">, "id" | "size"> {
77
size?: "sm" | "md";
88
icon?: React.ReactNode;
99
error?: string;
1010
extraText?: string;
1111
}
1212

13-
const InputField = forwardRef<HTMLInputElement, PropTypes>(({ size = "md", icon, error, extraText, className, ...props }: PropTypes, ref) => {
13+
const InputField = forwardRef<HTMLInputElement, PropTypes>(({ size = "md", title, icon, error, extraText, className, ...props }: PropTypes, ref) => {
1414
const id = useId();
1515

1616
return (
1717
<div>
18-
{props.title && (
18+
{title && (
1919
<label
2020
htmlFor={id}
2121
className={clsx("block font-medium text-gray-900 dark:text-white mb-1", {
2222
"text-xs": size === "sm",
2323
"text-sm": size === "md",
2424
})}
2525
>
26-
{props.title}
26+
{title}
2727
{props.required && <FontAwesomeIcon icon={faAsterisk} size="2xs" className="text-red-600 ml-1" />}
2828
</label>
2929
)}
@@ -37,7 +37,7 @@ const InputField = forwardRef<HTMLInputElement, PropTypes>(({ size = "md", icon,
3737
className={clsx(
3838
"text-sm rounded-lg block w-full",
3939
"bg-gray-50 border border-gray-300 text-gray-900 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white",
40-
"focus:ring-2 focus:ring-primary-300 focus:outline-none dark:focus:ring-primary-600",
40+
"focus:ring-2 focus:ring-primary-300 focus:outline-none dark:focus:ring-primary-800",
4141
{
4242
"border-red-500 text-red-900 placeholder-red-700 dark:text-red-500 dark:placeholder-red-500 dark:border-red-500": error !== undefined,
4343
"pl-8": !!icon,

src/components/general/SelectField.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,25 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
33
import clsx from "clsx";
44
import { useId } from "react";
55

6-
interface PropTypes extends Omit<React.ComponentProps<"select">, "size"> {
6+
interface PropTypes extends Omit<React.ComponentProps<"select">, "id" | "size"> {
77
size?: "sm" | "md";
88
error?: string;
99
}
1010

11-
const SelectField = ({ error, children, size = "md", placeholder, className, ...props }: PropTypes) => {
11+
const SelectField = ({ size = "md", title, error, children, placeholder, className, ...props }: PropTypes) => {
1212
const id = useId();
1313

1414
return (
1515
<div>
16-
{props.title && (
16+
{title && (
1717
<label
1818
htmlFor={id}
1919
className={clsx("block font-medium text-gray-900 dark:text-white mb-1", {
2020
"text-xs": size === "sm",
2121
"text-sm": size === "md",
2222
})}
2323
>
24-
{props.title}
24+
{title}
2525
{props.required && <FontAwesomeIcon icon={faAsterisk} size="2xs" className="text-red-600 ml-1" />}
2626
</label>
2727
)}
@@ -31,7 +31,7 @@ const SelectField = ({ error, children, size = "md", placeholder, className, ...
3131
className={clsx(
3232
"text-sm rounded-lg block w-full",
3333
"bg-gray-50 border border-gray-300 text-gray-900 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white ",
34-
"focus:ring-primary-300 focus:border-primary-300 dark:focus:ring-primary-600 dark:focus:border-primary-600",
34+
"focus:ring-primary-300 focus:border-primary-300 dark:focus:ring-primary-800 dark:focus:border-primary-800",
3535
{
3636
"p-1.5": size === "sm",
3737
"p-2.5": size === "md",

src/components/general/Switch.tsx

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import clsx from "clsx";
2+
3+
interface PropTypes {
4+
size?: "md" | "lg";
5+
name?: string;
6+
value: string;
7+
onChange?: (e: { target: { name?: string; value: string } }) => void;
8+
options: {
9+
value: string;
10+
name: string;
11+
}[];
12+
className?: string;
13+
}
14+
15+
const Switch = ({ size = "md", name, value, onChange, options, className }: PropTypes) => {
16+
return (
17+
<div
18+
className={clsx(
19+
"rounded-full flex items-center gap-x-1 w-fit bg-gray-50 text-gray-900 dark:bg-gray-700 dark:text-white",
20+
{
21+
"p-1": size === "md",
22+
"p-1.5": size === "lg",
23+
},
24+
className
25+
)}
26+
>
27+
{options.map((option) => (
28+
<div className="flex justify-center">
29+
<button
30+
type="button"
31+
className={clsx("w-full rounded-full", "focus:ring-2 focus:ring-primary-300 focus:outline-none dark:focus:ring-primary-800", {
32+
"bg-primary-600": value === option.value,
33+
"p-0.5 px-2": size === "md",
34+
"p-1 px-3": size === "lg",
35+
})}
36+
onClick={() => onChange?.({ target: { name: name, value: option.value } })}
37+
>
38+
{option.name}
39+
</button>
40+
</div>
41+
))}
42+
</div>
43+
);
44+
};
45+
46+
export default Switch;

src/components/general/TextareaField.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,25 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
33
import clsx from "clsx";
44
import { useId } from "react";
55

6-
interface PropTypes extends Omit<React.ComponentProps<"textarea">, "size"> {
6+
interface PropTypes extends Omit<React.ComponentProps<"textarea">, "id" | "size"> {
77
size?: "sm" | "md";
88
error?: string;
99
}
1010

11-
const TextareaField = ({ size = "md", error, value, rows = 3, className, ...props }: PropTypes) => {
11+
const TextareaField = ({ size = "md", title, error, value, rows = 3, className, ...props }: PropTypes) => {
1212
const id = useId();
1313

1414
return (
1515
<div>
16-
{props.title && (
16+
{title && (
1717
<label
1818
htmlFor={id}
1919
className={clsx("block font-medium text-gray-900 dark:text-white mb-1", {
2020
"text-xs": size === "sm",
2121
"text-sm": size === "md",
2222
})}
2323
>
24-
{props.title}
24+
{title}
2525
{props.required && <FontAwesomeIcon icon={faAsterisk} size="2xs" className="text-red-600 ml-1" />}
2626
</label>
2727
)}
@@ -32,7 +32,7 @@ const TextareaField = ({ size = "md", error, value, rows = 3, className, ...prop
3232
className={clsx(
3333
"text-sm rounded-lg block w-full",
3434
"bg-gray-50 border border-gray-300 text-gray-900 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white",
35-
"focus:ring-2 focus:ring-primary-300 focus:outline-none dark:focus:ring-primary-600",
35+
"focus:ring-2 focus:ring-primary-300 focus:outline-none dark:focus:ring-primary-800",
3636
{
3737
"border-red-500 text-red-900 placeholder-red-700 dark:text-red-500 dark:placeholder-red-500 dark:border-red-500": error !== undefined,
3838
"p-1.5": size === "sm",

src/components/general/Toast.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const Toast = ({ type, message, allowClose = true, onClose }: PropTypes) => {
3636
{allowClose && (
3737
<button
3838
type="button"
39-
className="ml-auto text-gray-400 hover:text-gray-900 rounded-lg p-1.5 inline-flex h-8 w-8 dark:text-gray-500 dark:hover:text-white focus:ring-2 focus:ring-primary-300 focus:outline-none dark:focus:ring-primary-600"
39+
className="ml-auto text-gray-400 hover:text-gray-900 rounded-lg p-1.5 inline-flex h-8 w-8 dark:text-gray-500 dark:hover:text-white focus:ring-2 focus:ring-primary-300 focus:outline-none dark:focus:ring-primary-800"
4040
aria-label="Close"
4141
onClick={onClose}
4242
>

src/components/general/Toggle.tsx

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import clsx from "clsx";
2+
import { useId } from "react";
3+
4+
interface PropTypes extends Omit<React.ComponentProps<"input">, "id" | "size" | "type"> {
5+
size?: "sm" | "md" | "lg";
6+
onLabel?: string;
7+
offLabel?: string;
8+
}
9+
10+
const Toggle = ({ size = "md", title, onLabel, offLabel, className, ...props }: PropTypes) => {
11+
const id = useId();
12+
13+
return (
14+
<label htmlFor={id} className={clsx("inline-flex items-center cursor-pointer", className)}>
15+
<input {...props} id={id} type="checkbox" className="sr-only peer" />
16+
<div
17+
className={clsx(
18+
"relative bg-gray-200 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-primary-300 dark:peer-focus:ring-primary-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:bg-white after:border-gray-300 after:border after:rounded-full after:transition-all dark:border-gray-600 peer-checked:bg-primary-600",
19+
{
20+
"w-7 h-4 after:h-3 after:w-3 after:top-[2px] after:left-[2px]": size === "sm",
21+
"w-9 h-5 after:h-4 after:w-4 after:top-[2px] after:left-[2px]": size === "md",
22+
"w-11 h-6 after:h-5 after:w-5 after:top-[2px] after:left-[2px]": size === "lg",
23+
}
24+
)}
25+
>
26+
{offLabel && (
27+
<span
28+
className={clsx("absolute font-normal uppercase text-white", {
29+
"text-[0.4rem] leading-3 uppercase right-0.5 top-0.5": size === "sm",
30+
"text-[0.5rem] leading-3 uppercase right-0.5 top-1": size === "md",
31+
"text-[0.6rem] leading-3 uppercase right-1 top-1.5": size === "lg",
32+
})}
33+
>
34+
{offLabel}
35+
</span>
36+
)}
37+
{onLabel && (
38+
<span
39+
className={clsx("absolute font-normal uppercase text-white", {
40+
"text-[0.4rem] leading-3 uppercase left-0.5 top-0.5": size === "sm",
41+
"text-[0.5rem] leading-3 uppercase left-0.5 top-1": size === "md",
42+
"text-[0.6rem] leading-3 uppercase left-1 top-1.5": size === "lg",
43+
})}
44+
>
45+
{onLabel}
46+
</span>
47+
)}
48+
</div>
49+
{title && (
50+
<span
51+
className={clsx("ml-2 font-medium text-gray-900 dark:text-gray-300", {
52+
"text-xs": size === "sm",
53+
"text-sm": size === "md",
54+
"text-base": size === "lg",
55+
})}
56+
>
57+
{title}
58+
</span>
59+
)}
60+
</label>
61+
);
62+
};
63+
64+
export default Toggle;

src/components/issues/EditTimer.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const EditTimer = ({ initTime, onOverrideTime, onCancel }: PropTypes) => {
2929
className={clsx(
3030
"text-lg rounded-md w-4 text-center appearance-none",
3131
"bg-gray-50 border border-gray-300 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400",
32-
"focus:ring-2 focus:ring-primary-300 focus:outline-none dark:focus:ring-primary-600",
32+
"focus:ring-2 focus:ring-primary-300 focus:outline-none dark:focus:ring-primary-800",
3333
initTime > 0 ? "text-yellow-500" : "text-gray-700 dark:text-gray-500"
3434
)}
3535
/**
@@ -66,7 +66,7 @@ const EditTimer = ({ initTime, onOverrideTime, onCancel }: PropTypes) => {
6666
className={clsx(
6767
"text-lg rounded-md w-6 text-center appearance-none",
6868
"bg-gray-50 border border-gray-300 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400",
69-
"focus:ring-2 focus:ring-primary-300 focus:outline-none dark:focus:ring-primary-600",
69+
"focus:ring-2 focus:ring-primary-300 focus:outline-none dark:focus:ring-primary-800",
7070
initTime > 0 ? "text-yellow-500" : "text-gray-700 dark:text-gray-500"
7171
)}
7272
onChange={(e) => {
@@ -92,7 +92,7 @@ const EditTimer = ({ initTime, onOverrideTime, onCancel }: PropTypes) => {
9292
className={clsx(
9393
"text-lg rounded-md w-6 text-center appearance-none",
9494
"bg-gray-50 border border-gray-300 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400",
95-
"focus:ring-2 focus:ring-primary-300 focus:outline-none dark:focus:ring-primary-600",
95+
"focus:ring-2 focus:ring-primary-300 focus:outline-none dark:focus:ring-primary-800",
9696
initTime > 0 ? "text-yellow-500" : "text-gray-700 dark:text-gray-500"
9797
)}
9898
onChange={(e) => {

0 commit comments

Comments
 (0)