【麹帳】管理画面作成
投稿日: 2025年02月22日
最近余計なことばかりしていて遅くなっていますが、麹帳に管理画面を作成しました。
多分ごくごく一般的な管理画面だと思います。
以前やらせていただいた実務案件で管理画面を6ページ作ったのですが、まさに同じような実装をしました。
その案件には検索や日付絞込み、ページネーションもありましたが今回は不要なのでなしです。
内容と技術的な部分も少し書いてみます。
目的はadminユーザーが麹調味料の公開申請を承認するための画面です。
supabaseの画面でも可能ですが、 技術力向上を目的としているので今回はあえて作成しました!
また、今回はロールがメインなら親麴調味料はnull、サブなら親麹調味料必須なので、そこはプログラム上でしか制御できないかなと思いました。
作りながら気づいただけで、だから作ったわけではないですw
私的に定番なreact-table使用しました。
セルの中で色んな操作が必要だったので、コンポーネント設計やステートをどこで管理するか、PUTリクエストをどうやって行うか悩みどころは多々ありました。
基本react-tableではcreateColumnHelperを使って定義する列データの定義ですべて済みました。列の定義を明確にできるおかげで、コンポーネントの分離がしやすくなると感じています。
例えば、親麹調味料なら
columnHelper.accessor("mainMaltArticle.id", {
header: "親麹調味料",
cell: info => {
const role = info.row.original.maltRole;
const articleId = info.row.original.id;
if (role === MaltRole.MAIN) {
return <div className="text-center">-</div>;
}
return <SelectMainMalt value={info.getValue()} articleId={articleId} />;
},
}),
こんな感じで、列の値の管理がコンポーネントに切り出すことでシンプルになりました。
というかそうしないとかなりステート管理が難しくすごくわかりにくくになると思います。
SelectMainMaltの中で更新処理も行いました。
import { useState } from "react";
import { useCategories } from "@/app/recipes/_hooks/useCategories";
import Select, { SingleValue } from "react-select";
import { api } from "@/app/_utils/api";
import { PutRequest } from "@/app/_types/Admin/malts/Parent/PutRequest";
import { useAdminMalts } from "../_hooks/useAdminMalts";
interface Props {
value: string | null;
articleId: string;
}
interface Option {
value: string;
label: string;
}
export const SelectMainMalt: React.FC<Props> = ({ value, articleId }) => {
const [malt, setMalt] = useState(value);
const { data, error } = useCategories();
const { mutate } = useAdminMalts();
const handleChange = async (selectedOption: SingleValue<Option>) => {
if (!selectedOption) return;
setMalt(selectedOption.value);
try {
await api.put<PutRequest, { message: string }>(
`/api/admin/malts/${articleId}/parent`,
{ parentId: selectedOption.value }
);
mutate();
} catch (e) {
console.error(e);
alert(e);
}
};
if (!data) return <div>取得中...</div>;
if (error) return <div>{error.message}</div>;
const options: Option[] = data.maltArticles.map(article => ({
value: article.id,
label: article.title,
}));
const selectedOption = options.find(option => option.value === malt);
return (
<Select
options={options}
value={selectedOption}
onChange={handleChange}
classNames={{
control: () => "!border-dark_brown !outline-none !text-dark_brown",
placeholder: () => "!text-dark_brown",
dropdownIndicator: () => "!text-dark_brown",
indicatorSeparator: () => "!bg-dark_brown",
singleValue: () => "!text-dark_brown",
}}
/>
);
};
テーブル操作結構難しいので、もうある程度書けるもののパターン経験したくて何度もしつこく書いて習得しようと頑張っています。
私は頭あんまり良くないし一度じゃ無理なのでとにかく繰り返しです。
次またユーザー向け機能の実装したいと思います。