Skip to content

Commit a961895

Browse files
committed
feat: add some component
1 parent 41d0a0a commit a961895

File tree

23 files changed

+155
-55
lines changed

23 files changed

+155
-55
lines changed

src/animations/variants.ts

+3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
export const pageVariants = {
22
initial: {
3+
opacity: 0,
34
x: '100vw',
45
},
56
in: {
7+
opacity: 1,
68
x: 0,
79
},
810
out: {
11+
opacity: 0,
912
x: '-100vw',
1013
},
1114
};

src/api/todo-list.ts

+6
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,14 @@ import {
44
ITodoListPost,
55
ITodoListEdit,
66
ITodoListDelete,
7+
ITodoListGet,
78
} from '@/types';
89

10+
export const getTodoList = async (id: ITodoListGet['id']) => {
11+
const { data } = await axios.get<ITodoList>('/todoList/' + id);
12+
return data;
13+
};
14+
915
export const createTodoList = async (body: ITodoListPost) => {
1016
const { data } = await axios.post<ITodoList>('/todoList', body);
1117
return data;

src/components/FormRHF/ColorPicker.tsx

+2-10
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,15 @@
1-
import { ColorPickerUI } from '@/components/FormUI';
2-
import { useController, useFormContext, useFormState } from 'react-hook-form';
3-
import ErrorMessage from '@/components/ErrorMessage';
4-
import { useTranslation } from '@/hooks/useTranslation';
5-
import type { IColorPickerUI } from '@/components/FormUI/ColorPickerUI';
1+
import { ColorPickerUI, IColorPickerUI } from '@/components/FormUI';
2+
import { useController } from 'react-hook-form';
63
import { RequiredName } from '@/types';
74

85
type IProps = RequiredName<Partial<IColorPickerUI>>;
96

107
const ColorPicker = ({ name, ...props }: IProps) => {
118
const { field } = useController({ name });
12-
const { errors } = useFormState({ name });
13-
const { t } = useTranslation();
14-
15-
const error = errors[name]?.message;
169

1710
return (
1811
<div>
1912
<ColorPickerUI {...props} {...field} />
20-
{/* <ErrorMessage>{t(error?.key, error?.values)}</ErrorMessage> */}
2113
</div>
2214
);
2315
};

src/components/FormRHF/TextArea.tsx

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { TextAreaUI, ITextAreaUI } from '@/components/FormUI';
2+
import { useFormContext, useFormState } from 'react-hook-form';
3+
import ErrorMessage from '@/components/ErrorMessage';
4+
import { useTranslation } from '@/hooks/useTranslation';
5+
import { IFormError, RequiredName } from '@/types';
6+
7+
type IProps = RequiredName<ITextAreaUI>;
8+
9+
const TextField = ({ name, ...props }: IProps) => {
10+
const { register } = useFormContext();
11+
const { errors } = useFormState({ name });
12+
const { t } = useTranslation();
13+
14+
const error = errors[name]?.message as IFormError;
15+
16+
return (
17+
<div>
18+
<TextAreaUI {...props} {...register(name)} />
19+
<ErrorMessage>{error && t(error)}</ErrorMessage>
20+
</div>
21+
);
22+
};
23+
24+
export default TextField;

src/components/FormRHF/TextField.tsx

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import { TextFieldUI } from '@/components/FormUI';
1+
import { TextFieldUI, ITextFieldUI } from '@/components/FormUI';
22
import { useFormContext, useFormState } from 'react-hook-form';
33
import ErrorMessage from '@/components/ErrorMessage';
44
import { useTranslation } from '@/hooks/useTranslation';
5-
import type { ITextFieldUI } from '@/components/FormUI/TextFieldUI';
6-
import { RequiredName } from '@/types';
5+
import { IFormError, RequiredName } from '@/types';
76

87
type IProps = RequiredName<ITextFieldUI>;
98

@@ -12,12 +11,12 @@ const TextField = ({ name, ...props }: IProps) => {
1211
const { errors } = useFormState({ name });
1312
const { t } = useTranslation();
1413

15-
const error = errors[name]?.message;
14+
const error = errors[name]?.message as IFormError;
1615

1716
return (
1817
<div>
1918
<TextFieldUI {...props} {...register(name)} />
20-
{/* <ErrorMessage>{t(error?.key, error?.values)}</ErrorMessage> */}
19+
<ErrorMessage>{error && t(error)}</ErrorMessage>
2120
</div>
2221
);
2322
};

src/components/FormRHF/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export { default as TextField } from './TextField';
2+
export { default as TextArea } from './TextArea';
23
export { default as ColorPicker } from './ColorPicker';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
.label {
2+
}
3+
4+
.textarea {
5+
width: 100%;
6+
outline: none;
7+
padding: 12px;
8+
background-color: transparent;
9+
border: none;
10+
border-bottom: 1px solid $color-twa-header;
11+
12+
transition: all 0.2s;
13+
14+
&:focus {
15+
border-color: $color-button;
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { ForwardedRef, TextareaHTMLAttributes, forwardRef } from 'react';
2+
import styles from './TextAreaUI.module.scss';
3+
4+
export interface ITextAreaUI
5+
extends TextareaHTMLAttributes<HTMLTextAreaElement> {
6+
label: string;
7+
}
8+
9+
const TextAreaUI = (
10+
{ label, ...props }: ITextAreaUI,
11+
ref: ForwardedRef<HTMLTextAreaElement>
12+
) => {
13+
return (
14+
<label className={styles.label}>
15+
<textarea
16+
ref={ref}
17+
className={styles.textarea}
18+
placeholder={label}
19+
{...props}
20+
/>
21+
</label>
22+
);
23+
};
24+
25+
export default forwardRef(TextAreaUI);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { default } from './TextAreaUI';
2+
export type { ITextAreaUI } from './TextAreaUI';

src/components/FormUI/index.ts

+6
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
export { default as TextFieldUI } from './TextFieldUI';
2+
export { default as TextAreaUI } from './TextAreaUI';
23
export { default as ColorPickerUI } from './ColorPickerUI';
4+
5+
//types
6+
export type { ITextFieldUI } from './TextFieldUI';
7+
export type { ITextAreaUI } from './TextAreaUI';
8+
export type { IColorPickerUI } from './ColorPickerUI';

src/containers/Category/Category.tsx

+3-4
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,15 @@ import Delete from '@/assets/icons/delete.svg';
77
import Edit from '@/assets/icons/edit.svg';
88
import { usePopup } from '@/hooks/usePopup';
99
import { useTranslation } from '@/hooks/useTranslation';
10-
import { useTodoLists } from '@/hooks/api/todo-list';
1110
import LinkButton from '@/components/LinkButton';
1211
import TodoList from '@/components/TodoList';
1312

1413
const Category = () => {
1514
const {
16-
query: { id },
15+
query: { categoryId },
1716
} = useRouter();
1817

19-
const { data, isLoading } = useCategory(id as string);
18+
const { data, isLoading } = useCategory(categoryId as string);
2019
const { open } = usePopup();
2120
const { t } = useTranslation();
2221

@@ -63,7 +62,7 @@ const Category = () => {
6362
</ContextMenu>
6463
</div>
6564
</div>
66-
<LinkButton href={`/create/category/${id}/todo-list`}>
65+
<LinkButton href={`/create/category/${categoryId}/todo-list`}>
6766
{t('new_todo_list')}
6867
</LinkButton>
6968
<div>

src/containers/CategoryForm/CategoryForm.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ interface IProps {
2222

2323
const CategoryForm = ({ type }: IProps) => {
2424
const {
25-
query: { id },
25+
query: { categoryId },
2626
} = useRouter();
2727

28-
const { data: category, isLoading } = useCategory(id as string);
28+
const { data: category, isLoading } = useCategory(categoryId as string);
2929

3030
const randomHexColor = useMemo(generateRandomHexColor, []);
3131

src/containers/TaskForm/TaskForm.tsx

+16-17
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { FormProvider, useForm } from 'react-hook-form';
22
import styles from './TaskForm.module.scss';
33
import { ColorPicker, TextField } from '@/components/FormRHF';
44
import { useMainButton } from '@/hooks/useMainButton';
5-
import { categorySchema } from '@/schema';
5+
import { categorySchema, taskSchema } from '@/schema';
66
import { generateRandomHexColor } from '@/utils';
77
import {
88
useCategory,
@@ -13,32 +13,32 @@ import { useTranslation } from '@/hooks/useTranslation';
1313
import { useClosingBehaviour } from '@/hooks/useClosingBehaviour';
1414
import { IFormType } from '@/types';
1515
import { useRouter } from '@/hooks/useRouter';
16-
import { useMemo } from 'react';
1716
import { yupResolver } from '@hookform/resolvers/yup';
17+
import { useCreateTask, useEditTask, useTask } from '@/hooks/api/task';
1818

1919
interface IProps {
2020
type: IFormType;
2121
}
2222

2323
const TaskForm = ({ type }: IProps) => {
2424
const {
25-
query: { id },
25+
query: { todoListId, taskId },
2626
} = useRouter();
2727

28-
const { data: category, isLoading } = useCategory(id as string);
29-
30-
const randomHexColor = useMemo(generateRandomHexColor, []);
28+
const { data: task, isLoading } = useTask({
29+
todoListId: todoListId as string,
30+
taskId: taskId as string,
31+
});
3132

3233
const methods = useForm({
33-
resolver: yupResolver(categorySchema),
34-
values: {
35-
title: category?.title ?? '',
36-
color: category?.color ?? randomHexColor,
37-
},
34+
resolver: yupResolver(taskSchema),
35+
// values: {
36+
37+
// },
3838
});
3939

40-
const { mutate: create, isLoading: isCreateLoading } = useCreateCategory();
41-
const { mutate: edit, isLoading: isEditLoading } = useEditCategory();
40+
const { mutate: create, isLoading: isCreateLoading } = useCreateTask();
41+
const { mutate: edit, isLoading: isEditLoading } = useEditTask();
4242

4343
const { t } = useTranslation();
4444

@@ -51,8 +51,8 @@ const TaskForm = ({ type }: IProps) => {
5151
if (type === 'create') {
5252
create(data);
5353
} else {
54-
if (!category?.id) return;
55-
edit({ ...data, id: category.id });
54+
if (!task?.id) return;
55+
edit({ ...data, id: task.id });
5656
}
5757
});
5858

@@ -74,8 +74,7 @@ const TaskForm = ({ type }: IProps) => {
7474
<h1>{t('new_category')}</h1>
7575
<FormProvider {...methods}>
7676
<form>
77-
<TextField name='title' label='Category name' />
78-
<ColorPicker name='color' label='Color' />
77+
<TextField name='title' label={t('task_name')} />
7978
</form>
8079
</FormProvider>
8180
</div>

src/hooks/api/task.ts

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import * as api from '@/api/task';
2+
import { useMutation } from '@tanstack/react-query';
3+
import { useTodoList } from './todo-list';
4+
5+
export const useTask = ({
6+
todoListId,
7+
taskId,
8+
}: {
9+
todoListId: string;
10+
taskId: string;
11+
}) => {
12+
const result = useTodoList(todoListId);
13+
const data = result.data?.tasks.find(task => task.id === taskId);
14+
15+
return {
16+
...result,
17+
data,
18+
};
19+
};
20+
21+
export const useCreateTask = () => {
22+
return useMutation({
23+
mutationFn: api.createTask,
24+
});
25+
};
26+
27+
export const useEditTask = () => {
28+
return useMutation({
29+
mutationFn: api.editTask,
30+
});
31+
};
32+
33+
export const useDeleteTask = () => {
34+
return useMutation({
35+
mutationFn: api.deleteTask,
36+
});
37+
};

src/hooks/api/todo-list.ts

+4-17
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,11 @@ import { useCategories, useCategory } from './category';
66
import { produce } from 'immer';
77
import { findTodoListById } from '@/utils';
88

9-
export const useTodoLists = (categoryId: string) => {
10-
const result = useCategory(categoryId);
11-
const data = result.data?.todoLists;
12-
13-
return {
14-
...result,
15-
data,
16-
};
17-
};
18-
199
export const useTodoList = (todoListId: string) => {
20-
const result = useCategories();
21-
const data = findTodoListById(result.data, todoListId);
22-
23-
return {
24-
...result,
25-
data,
26-
};
10+
return useQuery({
11+
queryKey: ['todo-list', todoListId],
12+
queryFn: () => api.getTodoList(todoListId),
13+
});
2714
};
2815

2916
export const useCreateTodoList = () => {
File renamed without changes.

src/pages/create/todo-list/index.tsx

Whitespace-only changes.
File renamed without changes.

src/pages/edit/task/[taskId].tsx

Whitespace-only changes.

src/pages/edit/todo-list/[todoListId].tsx

Whitespace-only changes.

src/types/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { Properties } from 'csstype';
22

33
export type RequiredName<T> = T & { name: string };
44

5+
export type IFormError = 'required';
6+
57
export type IFormType = 'create' | 'edit';
68
export interface ITask {
79
id: string;
@@ -24,6 +26,7 @@ export interface ITodoList {
2426
completed: number;
2527
tasks: ITask[];
2628
}
29+
export type ITodoListGet = Pick<ITodoList, 'id'>;
2730
export type ITodoListPost = Pick<ITodoList, 'title' | 'categoryId'>;
2831
export type ITodoListEdit = Pick<ITodoList, 'title' | 'categoryId' | 'id'>;
2932
export type ITodoListDelete = Pick<ITodoList, 'id'>;

0 commit comments

Comments
 (0)