refactor: separate url input components

This commit is contained in:
Mahen 2026-03-28 20:07:23 +07:00
parent a106c5d6c1
commit 1593fd75bd
5 changed files with 92 additions and 36 deletions

View File

@ -5,6 +5,7 @@ import { Sparkles, X } from "lucide-react";
import { Input } from "../ui/input"; import { Input } from "../ui/input";
import { Button } from "../ui/button"; import { Button } from "../ui/button";
import ResultSection from "./ResultSection"; import ResultSection from "./ResultSection";
import UrlInputList from "./UrlInputList";
export default function AnalysisClient() { export default function AnalysisClient() {
const { const {
@ -23,39 +24,6 @@ export default function AnalysisClient() {
setVisibleFields, setVisibleFields,
} = useAnalyseText(); } = useAnalyseText();
const urlInput = () => {
return urlDatas.slice(0, visibleFields).map((item, index) => (
<div
key={index}
className="animate-in fade-in slide-in-from-bottom-2 duration-300"
>
<label className="block mb-1 text-sm font-medium text-gray-700">
{item.labels}
</label>
<div className="flex gap-2">
<div className="flex-1">
<Input
type="url"
placeholder="Contoh: https://tokopedia.com/..."
className={`${item.errors ? "border-sentiment-negative" : "focus:ring-primary"}`}
{...item.title}
/>
</div>
{index === visibleFields - 1 && (
<Button
type="button"
variant="ghost"
onClick={() => setVisibleFields((prev) => prev - 1)}
className="text-sentiment-negative hover:text-sentiment-negative hover:bg-sentiment-negative-light shrink-0"
>
</Button>
)}
</div>
</div>
));
};
return ( return (
<div className="w-full mx-auto"> <div className="w-full mx-auto">
<form <form
@ -105,7 +73,11 @@ export default function AnalysisClient() {
</div> </div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 items-end transition-all duration-500"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4 items-end transition-all duration-500">
{urlInput()} <UrlInputList
urlDatas={urlDatas}
visibleFields={visibleFields}
setVisibleFields={setVisibleFields}
/>
{visibleFields < 2 && ( {visibleFields < 2 && (
<div <div

View File

@ -0,0 +1,40 @@
import { UrlInputItemProps } from "@/src/types";
import { Button } from "../ui/button";
import { Input } from "../ui/input";
const UrlInputItem = ({
item,
index,
visibleFields,
onRemove,
}: UrlInputItemProps) => {
return (
<div className="animate-in fade-in slide-in-from-bottom-2 duration-300">
<label className="block mb-1 text-sm font-medium text-gray-700">
{item.labels}
</label>
<div className="flex gap-2">
<div className="flex-1">
<Input
type="url"
placeholder="Contoh: https://tokopedia.com/..."
className={`${item.errors ? "border-sentiment-negative" : "focus:ring-primary"}`}
{...item.title}
/>
</div>
{index === visibleFields - 1 && (
<Button
type="button"
variant="ghost"
onClick={onRemove}
className="text-sentiment-negative hover:text-sentiment-negative hover:bg-sentiment-negative-light shrink-0"
>
</Button>
)}
</div>
</div>
);
};
export default UrlInputItem;

View File

@ -0,0 +1,24 @@
import { UrlInputListProps } from "@/src/types";
import UrlInputItem from "./UrlInputItem";
const UrlInputList = ({
urlDatas,
visibleFields,
setVisibleFields,
}: UrlInputListProps) => {
return (
<>
{urlDatas.slice(0, visibleFields).map((item, index) => (
<UrlInputItem
key={index}
item={item}
index={index}
visibleFields={visibleFields}
onRemove={() => setVisibleFields((prev) => prev - 1)}
/>
))}
</>
);
};
export default UrlInputList;

0
src/hooks/useUrlInput.ts Normal file
View File

View File

@ -5,6 +5,7 @@ import { profileSchema } from "../app/validation/profile.schema";
import { Session } from "next-auth"; import { Session } from "next-auth";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { analyzeSchema } from "../app/validation/analyze.schema"; import { analyzeSchema } from "../app/validation/analyze.schema";
import { FieldError, UseFormRegisterReturn } from "react-hook-form";
export interface ModelDB { export interface ModelDB {
modelName: string; modelName: string;
@ -19,7 +20,7 @@ export interface ModelDB {
export interface ProfileClientProps { export interface ProfileClientProps {
name: string; name: string;
bio?: string; bio?: string;
preferenceBrand: string preferenceBrand: string;
preferenceOS: string; preferenceOS: string;
budgetMin: number; budgetMin: number;
budgetMax: number; budgetMax: number;
@ -372,3 +373,22 @@ export interface AnalysisWithMetric {
name: string; name: string;
} | null; } | null;
} }
type UrlData = {
labels: string;
errors: FieldError | undefined;
title: UseFormRegisterReturn;
};
export type UrlInputItemProps = {
item: UrlData;
index: number;
visibleFields: number;
onRemove: () => void;
};
export type UrlInputListProps = {
urlDatas: UrlData[];
visibleFields: number;
setVisibleFields: React.Dispatch<React.SetStateAction<number>>;
};