Skip to content

Commit 657fecd

Browse files
committed
add: components in frontend_1
1 parent 91d0c47 commit 657fecd

File tree

16 files changed

+233
-5
lines changed

16 files changed

+233
-5
lines changed

Diff for: README.md

-1
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,3 @@
4646
- React
4747
- Next.js
4848
- App Router
49-
- Radix UI

Diff for: frontend_5/.eslintrc.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ module.exports = {
2424
groups: ['builtin', 'external', 'internal', 'unknown'],
2525
pathGroups: [
2626
{
27-
pattern: '{@chakra-ui,@storybook}/**',
27+
pattern: '{a}/**',
2828
group: 'external',
2929
position: 'after'
3030
}

Diff for: frontend_5/package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
"dependencies": {
55
"next": "13.4.6",
66
"react": "18.2.0",
7-
"react-dom": "18.2.0"
7+
"react-dom": "18.2.0",
8+
"react-icons": "4.9.0",
9+
"recoil": "0.7.7"
810
},
911
"devDependencies": {
1012
"@tsconfig/strictest": "2.0.1",

Diff for: frontend_5/pnpm-lock.yaml

+36-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: frontend_5/src/components/atoms/Button.tsx

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
type Props = {
2+
onClick: () => void
3+
children: React.ReactNode
4+
}
5+
6+
export const Button: React.FC<Props> = ({ onClick, children }) => (
7+
<button type="button" onClick={() => onClick()}>
8+
{children}
9+
</button>
10+
)

Diff for: frontend_5/src/components/atoms/Icon.tsx

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { createElement } from 'react'
2+
import { FaSyncAlt } from 'react-icons/fa'
3+
4+
const icons = {
5+
sync: FaSyncAlt
6+
}
7+
8+
type Props = {
9+
name: keyof typeof icons
10+
onClick?: (() => void) | undefined
11+
}
12+
13+
const getIcon = ({ name, onClick }: Props) => createElement(icons[name], { onClick })
14+
15+
export const Icon: React.FC<Props> = ({ name, onClick }) => getIcon({ name, onClick })

Diff for: frontend_5/src/components/atoms/Label.tsx

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
type Props = {
2+
children: React.ReactNode
3+
}
4+
5+
export const Label: React.FC<Props> = ({ children }) => <span>{children}</span>

Diff for: frontend_5/src/components/atoms/Loading.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const Loading: React.FC = () => <span>Loading...</span>

Diff for: frontend_5/src/components/atoms/Table.tsx

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
type AnonymousUnion = keyof { [key: string]: unknown }
2+
3+
export type Columns<T> = {
4+
id: T
5+
label: string
6+
}[]
7+
8+
type Row<T extends AnonymousUnion> = {
9+
[P in T]: { content: string; el?: JSX.Element } | { content?: string; el: JSX.Element }
10+
}
11+
export type RowEl<T, C extends AnonymousUnion> = (r: T) => Row<C>
12+
13+
export type Rows<T extends unknown[]> = T
14+
15+
type Props<T extends AnonymousUnion> = {
16+
columns: Columns<T>
17+
rowEl: RowEl<any, T>
18+
rows: Rows<unknown[]>
19+
}
20+
21+
export const Table: React.FC<Props<AnonymousUnion>> = ({ columns, rowEl, rows }) => (
22+
<table>
23+
<thead>
24+
<tr>
25+
{columns.map(c => (
26+
<th key={c.id}>{c.label}</th>
27+
))}
28+
</tr>
29+
</thead>
30+
<tbody>
31+
{rows.map(r => (
32+
<tr key={rowEl(r)['id']?.content}>
33+
{columns.map(c => {
34+
const re = rowEl(r)[c.id]
35+
return re ? <td key={c.id}>{re.content ? re.content : re.el}</td> : <td key={c.id} />
36+
})}
37+
</tr>
38+
))}
39+
</tbody>
40+
</table>
41+
)

Diff for: frontend_5/src/components/atoms/TextInput.tsx

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
type Props = {
2+
value: string
3+
onChange: (v: string) => void
4+
}
5+
6+
export const TextInput: React.FC<Props> = ({ value, onChange }) => (
7+
<input type="text" value={value} onChange={e => onChange(e.target.value)} />
8+
)
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { Label } from '@/components/atoms/Label'
2+
import { TextInput } from '@/components/atoms/TextInput'
3+
4+
type Props = {
5+
label: string
6+
value: string
7+
onChange: (v: string) => void
8+
}
9+
10+
export const LabeledTextInput: React.FC<Props> = ({ label, value, onChange }) => (
11+
<>
12+
<Label>{label}</Label>
13+
<TextInput value={value} onChange={onChange} />
14+
</>
15+
)
+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { useState } from 'react'
2+
import { useRecoilState } from 'recoil'
3+
4+
import { Button } from '@/components/atoms/Button'
5+
import { LabeledTextInput } from '@/components/molecules/LabeledTextInput'
6+
import { EmployeeTable } from '@/features/employee/components/EmployeeTable'
7+
import type { Employee as EmployeeType } from '@/features/employee/types'
8+
import { employeeState } from '@/store/employee'
9+
10+
export const Employee: React.FC = () => {
11+
const [employee, setEmployee] = useRecoilState(employeeState)
12+
const [employees] = useState<EmployeeType[]>([])
13+
// const [employees, setEmployees] = useState<EmployeeType[]>([])
14+
15+
// const fetchEmployeesAction = useAction(fetchEmployees)
16+
// const updateEmployeeAction = useAction(updateEmployee)
17+
18+
// const fetchToSetEmployees = useCallback(
19+
// () =>
20+
// fetchEmployeesAction().then(r => {
21+
// setEmployees(r)
22+
// }),
23+
// [fetchEmployeesAction]
24+
// )
25+
26+
// useEffect(() => {
27+
// fetchToSetEmployees().catch(e => {
28+
// throw e
29+
// })
30+
// }, [fetchToSetEmployees])
31+
32+
// const handleClick = () => {
33+
// updateEmployeeAction(new EmployeeUpdateCommand(employee, company)).catch((e: Error) => {
34+
// console.error({ 'event-handler-error': e })
35+
// })
36+
// }
37+
38+
return (
39+
<>
40+
<LabeledTextInput
41+
label="社員ID"
42+
value={employee.employeeId}
43+
onChange={v => setEmployee({ ...employee, employeeId: v })}
44+
/>
45+
<LabeledTextInput
46+
label="社員名"
47+
value={employee.employeeName}
48+
onChange={v => setEmployee({ ...employee, employeeName: v })}
49+
/>
50+
<Button onClick={() => undefined}>登録</Button>
51+
{/* <Button onClick={handleClick}>登録</Button> */}
52+
<EmployeeTable {...{ employees, onSync: () => undefined }} />
53+
{/* <EmployeeTable {...{ employees, onSync: fetchToSetEmployees }} /> */}
54+
</>
55+
)
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { Icon } from '@/components/atoms/Icon'
2+
import type { Columns, RowEl, Rows } from '@/components/atoms/Table'
3+
import { Table } from '@/components/atoms/Table'
4+
import type { Employee } from '@/features/employee/types'
5+
6+
type Column = 'id' | 'employeeId' | 'employeeName'
7+
8+
type Props = {
9+
employees: Rows<Employee[]>
10+
onSync: () => void
11+
}
12+
13+
export const EmployeeTable: React.FC<Props> = ({ employees, onSync }) => {
14+
const columns: Columns<Column> = [
15+
{ id: 'employeeId', label: '社員ID' },
16+
{ id: 'employeeName', label: '社員名' }
17+
]
18+
19+
const rowEl: RowEl<Employee, Column> = e => ({
20+
id: { content: e.employeeId },
21+
employeeId: { content: e.employeeId },
22+
employeeName: { content: e.employeeName }
23+
})
24+
25+
return (
26+
<>
27+
<Table {...{ columns, rowEl, rows: employees }} />
28+
<Icon name="sync" onClick={onSync} />
29+
</>
30+
)
31+
}

Diff for: frontend_5/src/features/employee/types/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export type Employee = {
2+
employeeId: string
3+
employeeName: string
4+
}

Diff for: frontend_5/src/store/employee.ts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { atom } from 'recoil'
2+
3+
export const employeeState = atom({
4+
key: 'employeeState',
5+
default: { employeeId: 'default', employeeName: 'デフォルト' }
6+
})

Diff for: frontend_5/tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"incremental": false,
55
"target": "esnext",
66
"module": "esnext",
7-
"lib": [],
7+
"lib": ["dom", "dom.iterable", "esnext"],
88
"allowJs": true,
99
"jsx": "preserve",
1010
"sourceMap": true,

0 commit comments

Comments
 (0)