feat: add removable reference feature vertical slice

This commit is contained in:
donghyeon-ka
2026-07-26 14:56:34 +09:00
parent 980981bc86
commit c11be43f20
87 changed files with 1881 additions and 1114 deletions
@@ -0,0 +1,60 @@
import { useState, type FormEvent } from "react";
import { AsyncSurface } from "../../../presentation/components/async-surface.jsx";
import { Button } from "../../../presentation/components/ui/button.jsx";
import { PageHeader } from "../../../presentation/components/page-header.jsx";
import { useReferenceFeature } from "./use-reference-feature.js";
export default function ReferenceResourcePage() {
const { filters, query, mutation } = useReferenceFeature();
const [name, setName] = useState("");
async function submit(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
const result = await mutation.submit({ name });
if (result.ok) setName("");
}
return (
<section className="ui-page">
<PageHeader
eyebrow="제거 가능한 수직 슬라이스"
title="Reference feature"
description="URL codec, application input, HTTP/schema/mapper와 query/mutation 상태를 한 경로로 검증합니다."
/>
<p data-testid="reference-filter">
limit {filters.limit}
{filters.tags?.length ? ` · tags ${filters.tags.join(", ")}` : ""}
</p>
<AsyncSurface state={query.state} onRetry={query.retry}>
<ul aria-label="Reference resources">
{(query.data ?? []).map((resource) => (
<li
key={resource.resourceId}
data-optimistic={resource.optimistic || undefined}
>
{resource.title}
</li>
))}
</ul>
</AsyncSurface>
<AsyncSurface
state={mutation.state}
onResolveConflict={mutation.resolveConflict}
>
<form onSubmit={(event) => void submit(event)}>
<label htmlFor="reference-resource-name"> </label>
<input
id="reference-resource-name"
value={name}
onChange={(event) => setName(event.currentTarget.value)}
required
/>
<Button type="submit" disabled={mutation.state.overlay.mutationPending}>
</Button>
</form>
</AsyncSurface>
</section>
);
}