refactor: colocate frontend component files
Frontend security / security (push) Successful in 9s
Frontend verify / verify (push) Successful in 5m10s
Conventional commits / commits (pull_request) Successful in 25s
Frontend security / security (pull_request) Successful in 9s
Frontend verify / verify (pull_request) Successful in 5m10s
Frontend security / security (push) Successful in 9s
Frontend verify / verify (push) Successful in 5m10s
Conventional commits / commits (pull_request) Successful in 25s
Frontend security / security (pull_request) Successful in 9s
Frontend verify / verify (pull_request) Successful in 5m10s
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
import { Alert } from "@mantine/core";
|
||||
import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||
import { type FC, useState } from "react";
|
||||
import { FormProvider, useForm, useWatch } from "react-hook-form";
|
||||
import type { OperationValues } from "./OperationForm.types";
|
||||
import { OperationFormView } from "./OperationForm.view";
|
||||
|
||||
type ExampleProps = { pending?: boolean; conflict?: boolean };
|
||||
const OperationExample: FC<ExampleProps> = (props) => {
|
||||
const [opened, setOpened] = useState(true);
|
||||
const [action, setAction] = useState("");
|
||||
const methods = useForm<OperationValues>({
|
||||
defaultValues: {
|
||||
kind: "refund",
|
||||
cardId: "demo",
|
||||
targetCardId: "",
|
||||
categoryId: "",
|
||||
originalExpenseId: "purchase",
|
||||
amount: "500",
|
||||
date: "2026-08-01",
|
||||
description: "Синтетический возврат",
|
||||
},
|
||||
});
|
||||
const kind = useWatch({ control: methods.control, name: "kind" });
|
||||
return (
|
||||
<FormProvider {...methods}>
|
||||
<OperationFormView
|
||||
opened={opened}
|
||||
pending={Boolean(props.pending)}
|
||||
editing
|
||||
categoriesOpen={false}
|
||||
onClose={() => !props.pending && setOpened(false)}
|
||||
onCancel={() => setOpened(false)}
|
||||
onExitTransitionEnd={() => setAction("Форма закрыта")}
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
setAction("Локальный submit");
|
||||
}}
|
||||
fields={{
|
||||
editing: true,
|
||||
refundCardId: "demo",
|
||||
kind,
|
||||
cards: [{ value: "demo", label: "Учебная карта" }],
|
||||
targets: [],
|
||||
categories: [],
|
||||
defaultCategory: "",
|
||||
kinds: [{ value: "refund", label: "Возврат" }],
|
||||
dateInputValue: () => "2026-08-01",
|
||||
validDate: (value) => value === "2026-08-01",
|
||||
maxDate: () => "2026-08-27",
|
||||
}}
|
||||
refund={{
|
||||
editing: true,
|
||||
expenses: [
|
||||
{
|
||||
value: "purchase",
|
||||
label: "01.07.2026 · Учебная покупка · 500 ₽",
|
||||
},
|
||||
],
|
||||
onSelect: () => undefined,
|
||||
limit: { currency: "RUB", value: "500" },
|
||||
}}
|
||||
loadingExpenses={false}
|
||||
emptyExpenses={false}
|
||||
sourcePage={1}
|
||||
previousDisabled
|
||||
nextDisabled
|
||||
onPrevious={() => undefined}
|
||||
onNext={() => undefined}
|
||||
onAddCategory={() => undefined}
|
||||
saveDisabled={false}
|
||||
feedback={
|
||||
props.conflict && (
|
||||
<Alert color="orange" role="alert">
|
||||
Синтетический конфликт версии
|
||||
</Alert>
|
||||
)
|
||||
}
|
||||
onReload={
|
||||
props.conflict ? () => setAction("Локальный reload") : undefined
|
||||
}
|
||||
latest={
|
||||
props.conflict
|
||||
? {
|
||||
version: 2,
|
||||
details: "Учебная версия",
|
||||
onAdopt: () => setAction("Локальное принятие версии"),
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
<output aria-live="polite">{action}</output>
|
||||
</FormProvider>
|
||||
);
|
||||
};
|
||||
const meta = {
|
||||
title: "Product/OperationForm",
|
||||
component: OperationExample,
|
||||
tags: ["autodocs"],
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
component:
|
||||
"Synthetic presentation без API/VM. Date callbacks фиксируют fixture 01.08.2026; денежная validation, recovery и nested category flow проверяются application tests. Actions только локальные.",
|
||||
},
|
||||
},
|
||||
},
|
||||
} satisfies Meta<typeof OperationExample>;
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
export const Refund: Story = {};
|
||||
export const Pending: Story = { args: { pending: true } };
|
||||
export const Conflict: Story = { args: { conflict: true } };
|
||||
Reference in New Issue
Block a user