Skip to content

Commit

Permalink
🔄 Merge pull request #6 from steeeee0223/feature/ui
Browse files Browse the repository at this point in the history
Add hooks & fix linting message
  • Loading branch information
steeeee0223 authored Jan 24, 2024
2 parents d1e4c41 + 7ead6f6 commit 18ed156
Show file tree
Hide file tree
Showing 13 changed files with 84 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
"use client";

Expand Down
2 changes: 2 additions & 0 deletions packages/ui/src/components/custom/crud-item/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable jsx-a11y/interactive-supports-focus */
/* eslint-disable jsx-a11y/click-events-have-key-events */
"use client";

import type { MouseEvent } from "react";
Expand Down
4 changes: 0 additions & 4 deletions packages/ui/src/components/custom/kanban/kanban-container.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */

"use client";

import type { OnDragEndResponder } from "@hello-pangea/dnd";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
"use client";

import type { KeyboardEventHandler } from "react";
Expand Down
1 change: 0 additions & 1 deletion packages/ui/src/components/custom/kanban/kanban-item.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
"use client";

import { Draggable } from "@hello-pangea/dnd";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
"use client";

import { useImperativeHandle, useRef, useState, useTransition } from "react";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
"use client";

import { useImperativeHandle, useRef, useState, useTransition } from "react";
Expand Down
1 change: 0 additions & 1 deletion packages/ui/src/components/custom/kanban/kanban-list.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
"use client";

import { useRef, useState } from "react";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
"use client";

import * as React from "react";
Expand Down
1 change: 1 addition & 0 deletions packages/ui/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./use-action";
export * from "./use-fetch";
export * from "./use-scroll-top";
58 changes: 58 additions & 0 deletions packages/ui/src/hooks/use-action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"use client";

import { useCallback, useState } from "react";

import { ActionHandler, FieldErrors } from "@/lib";

interface UseActionOptions<TOutput> {
onSuccess?: (data: TOutput) => void;
onError?: (error: string) => void;
onComplete?: () => void;
}

interface UseActionResult<TInput, TOutput> {
execute: (data: TInput) => Promise<void>;
fieldErrors?: FieldErrors<TInput>;
error?: string;
data?: TOutput;
isLoading: boolean;
}

export const useAction = <TInput, TOutput>(
action: ActionHandler<TInput, TOutput>,
options: UseActionOptions<TOutput>,
): UseActionResult<TInput, TOutput> => {
const [fieldErrors, setFieldErrors] = useState<
FieldErrors<TInput> | undefined
>(undefined);
const [error, setError] = useState<string | undefined>(undefined);
const [data, setData] = useState<TOutput | undefined>(undefined);
const [isLoading, setIsLoading] = useState<boolean>(false);

const execute = useCallback(
async (input: TInput) => {
setIsLoading(true);
try {
const result = await action(input);
if (!result) return;

const { fieldErrors, error, data } = result;
setFieldErrors(fieldErrors);
if (error) {
setError(error);
options.onError?.(error);
}
if (data) {
setData(data);
options.onSuccess?.(data);
}
} finally {
setIsLoading(false);
options.onComplete?.();
}
},
[action, options],
);

return { execute, fieldErrors, error, data, isLoading };
};
18 changes: 18 additions & 0 deletions packages/ui/src/lib/action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { z } from "zod";

import type { ActionHandler, FieldErrors } from "./types";

export const createSafeAction =
<TInput, TOutput>(
schema: z.Schema<TInput>,
handler: ActionHandler<TInput, TOutput>,
): ActionHandler<TInput, TOutput> =>
async (data) => {
const result = schema.safeParse(data);
return result.success
? await handler(result.data)
: {
fieldErrors: result.error.flatten()
.fieldErrors as FieldErrors<TInput>,
};
};
3 changes: 2 additions & 1 deletion packages/ui/src/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./utils";
export * from "./action";
export * from "./types";
export * from "./utils";

0 comments on commit 18ed156

Please sign in to comment.