Skip to content

Commit e6b3536

Browse files
committed
JSONビューアーと永続処理の追加
1 parent 0cf965b commit e6b3536

8 files changed

Lines changed: 305 additions & 4 deletions

File tree

.replit

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
modules = ["nodejs-20"]
1+
modules = ["nodejs-20", "nodejs-21"]
22
run = "yarn run dev"
33

44
[nix]

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"react": "^18.3.1",
3535
"react-dom": "^18.3.1",
3636
"react-hook-form": "^7.53.0",
37+
"react-json-view": "^1.21.3",
3738
"rsuite": "^5.70.0",
3839
"timezones-list": "^3.0.3",
3940
"uuid": "^10.0.0"

src/app/json_view/JsonView.tsx

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
'use client';
2+
import React, { FC } from 'react';
3+
import { Controller, FormProvider } from 'react-hook-form';
4+
import { Col, Grid, Panel, PanelGroup, Row } from 'rsuite';
5+
import ReactJson from 'react-json-view';
6+
import { AppLayout } from '@/Layout/App';
7+
import { useJsonView } from '@/app/json_view/useJsonView';
8+
import { Editor, ex } from '@/components/common/Editor';
9+
import { ClearButton } from '@/components/common/Form/ClearButton';
10+
import { CopyButton } from '@/components/common/Form/CopyButton';
11+
import { PageTitle } from '@/components/common/PageTitle';
12+
import { PanelHeader } from '@/components/common/PanelHeader';
13+
14+
export const JsonView: FC = () => {
15+
const title = 'JSONビューアー';
16+
const { input, methods } = useJsonView();
17+
18+
return (
19+
<FormProvider {...methods}>
20+
<AppLayout>
21+
<Grid fluid>
22+
<PageTitle title={title} />
23+
<Row gutter={5}>
24+
<Col xs={24} md={12}>
25+
<PanelGroup bordered>
26+
<Panel
27+
bordered
28+
header={<PanelHeader title="入力" right={<ClearButton name="input" />} />}
29+
>
30+
<Controller
31+
render={({ field }) => <Editor extensions={[ex.json]} {...field} />}
32+
name="input"
33+
control={methods.control}
34+
/>
35+
</Panel>
36+
</PanelGroup>
37+
</Col>
38+
<Col xs={24} md={12}>
39+
<Panel
40+
bordered
41+
header={
42+
<PanelHeader
43+
title="JSON"
44+
right={<CopyButton size="small" copyText={JSON.stringify(input)} />}
45+
/>
46+
}
47+
>
48+
<ReactJson
49+
src={input}
50+
theme="chalk"
51+
style={{ padding: '4px', border: '1px solid #a4a9b3', borderRadius: '6px' }}
52+
/>
53+
</Panel>
54+
</Col>
55+
</Row>
56+
</Grid>
57+
</AppLayout>
58+
</FormProvider>
59+
);
60+
};

src/app/json_view/page.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React, { FC } from 'react';
2+
import { JsonView } from './JsonView';
3+
4+
export const metadata = {
5+
title: 'Dev Toolkit - JSONビューアー',
6+
};
7+
8+
const JsonViewPage: FC = () => {
9+
return <JsonView />;
10+
};
11+
12+
export default JsonViewPage;

src/app/json_view/useJsonView.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { useCustomForm } from '@/components/common/Form/useCustomForm';
2+
import { useFormPersistence } from '@/hooks/useFormPersistence';
3+
4+
type JsonFormatForm = {
5+
input: string;
6+
};
7+
8+
const DEFAULT_VALUES: JsonFormatForm = {
9+
input: '',
10+
};
11+
12+
export const useJsonView = () => {
13+
const methods = useCustomForm<JsonFormatForm>({
14+
defaultValues: DEFAULT_VALUES,
15+
});
16+
const { watch, setValue } = methods;
17+
useFormPersistence('json_view', methods, (defaultValues) => {
18+
setValue('input', defaultValues?.input);
19+
});
20+
21+
const input = toJson(watch('input', DEFAULT_VALUES.input));
22+
23+
return {
24+
DEFAULT_VALUES,
25+
methods,
26+
input,
27+
};
28+
};
29+
30+
const toJson = (input: string): object => {
31+
try {
32+
return JSON.parse(input);
33+
} catch {
34+
return {};
35+
}
36+
};

src/components/common/Features.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ export const features: FeatureGroupType[] = [
7474
title: 'JSONフォーマット',
7575
path: '/json_formatter',
7676
},
77+
{
78+
key: 'json_view',
79+
title: 'JSONビューアー',
80+
path: '/json_view',
81+
},
7782
],
7883
},
7984
{

src/hooks/useFormPersistence.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { useEffect } from 'react';
2+
import type { UseFormReturn } from 'react-hook-form';
3+
4+
// フォームの情報をlocalStorageに保存して永続化する
5+
export const useFormPersistence = <T>(
6+
name: string,
7+
methods: UseFormReturn<T>,
8+
setCallback: (defaultValues: T) => void,
9+
) => {
10+
const {
11+
watch,
12+
formState: { isDirty },
13+
} = methods;
14+
const formData = watch();
15+
16+
useEffect(() => {
17+
const defaultValues = JSON.parse(localStorage.getItem(name));
18+
if (!isDirty) {
19+
setCallback(defaultValues);
20+
}
21+
}, [isDirty]);
22+
23+
useEffect(() => {
24+
if (isDirty) {
25+
localStorage.setItem(name, JSON.stringify(formData));
26+
console.log('set', isDirty, formData);
27+
}
28+
}, [formData, isDirty]);
29+
};

0 commit comments

Comments
 (0)