62 lines
1.5 KiB
React
62 lines
1.5 KiB
React
import { useEffect, useState } from "react";
|
|
|
|
import { deriveAsyncState } from "../../application/view-models/async-state.js";
|
|
import { AsyncSurface } from "../../presentation/components/async-surface.jsx";
|
|
|
|
/**
|
|
* @typedef {{
|
|
* loading: boolean,
|
|
* resources?: Array<{resourceId: string, title: string, createdAtLabel: string | null}>,
|
|
* failure?: import("../../contracts/errors.js").ApiFailure
|
|
* }} SamplePageState
|
|
*/
|
|
|
|
/**
|
|
* @param {{
|
|
* facade: ReturnType<typeof import("./sample-facade.js").createSampleFacade>
|
|
* }} props
|
|
*/
|
|
export function SampleResourcePage({ facade }) {
|
|
const [result, setResult] = useState(
|
|
/** @type {SamplePageState} */ ({
|
|
loading: true,
|
|
resources: undefined,
|
|
failure: undefined,
|
|
}),
|
|
);
|
|
|
|
useEffect(() => {
|
|
let active = true;
|
|
void facade.listResources().then((outcome) => {
|
|
if (!active) return;
|
|
setResult(
|
|
outcome.ok
|
|
? { loading: false, resources: outcome.value, failure: undefined }
|
|
: { loading: false, resources: undefined, failure: outcome.error },
|
|
);
|
|
});
|
|
return () => {
|
|
active = false;
|
|
};
|
|
}, [facade]);
|
|
|
|
const state = deriveAsyncState({
|
|
isInitialLoading: result.loading,
|
|
data: result.resources,
|
|
failure: result.failure,
|
|
});
|
|
|
|
return (
|
|
<main>
|
|
<h1>샘플 리소스</h1>
|
|
<AsyncSurface state={state}>
|
|
<ul>
|
|
{(result.resources ?? []).map((resource) => (
|
|
<li key={resource.resourceId}>{resource.title}</li>
|
|
))}
|
|
</ul>
|
|
</AsyncSurface>
|
|
</main>
|
|
);
|
|
}
|