Skip to content
This repository has been archived by the owner on Aug 2, 2023. It is now read-only.

リーダー管理画面の実装 #42

Merged
merged 3 commits into from
Mar 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"react": "18.2.0",
"react-dom": "18.2.0",
"react-feather": "^2.0.10",
"react-hooks-use-modal": "^3.3.1",
"react-icons": "^4.7.1",
"superjson": "1.9.1",
"zod": "^3.18.0"
Expand Down
18 changes: 18 additions & 0 deletions src/components/GeneralDivider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react'

type GeneralDividerProps = {
label: string
}

function GeneralDivider({ label }: GeneralDividerProps) {
return (
<div className='flex w-full items-center justify-center'>
<hr className='my-8 h-px w-80 border-0 bg-gray-600 md:w-96' />
<span className='absolute left-1/3 -translate-x-1/2 bg-white px-4 text-lg font-medium text-gray-900 md:left-1/2'>
{label}
</span>
</div>
)
}

export default GeneralDivider
129 changes: 127 additions & 2 deletions src/components/ReaderBody.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,134 @@
import React from 'react'
import React, { useEffect, useRef, useState } from 'react'
import { Plus } from 'react-feather'
import { useModal } from 'react-hooks-use-modal'
import { trpc } from '../utils/trpc'
import GeneralDivider from './GeneralDivider'
import ReaderCard from './ReaderCard'

type Reader = {
client_id: string
name: string
}

type AddReaderResponse = {
name: string
client_id: string
client_token: string
}

function ReaderBody() {
const { data, isLoading, refetch } = trpc.reader.showReaders.useQuery()
const [readers, setReaders] = useState<Reader[]>([])
const label = isLoading ? 'カードリーダー: 取得中...' : `カードリーダー: ${data?.length}台`

const [newReader, setNewReader] = useState<AddReaderResponse>()

const [AddReaderModal, openAddReaderModal, closeAddReaderModal] = useModal('__next', {
preventScroll: true
})

const [NewReaderModal, openNewReaderModal, closeNewReaderModal] = useModal('__next', {
preventScroll: true
})

const addReaderMutation = trpc.reader.registerReader.useMutation({
onSuccess: data => {
refetch()
setNewReader({
name: data.name,
client_id: data.client_id,
client_token: data.client_token
})
openNewReaderModal()
}
})

const addReader = () => {
addReaderMutation.mutate({
name: inputRef.current?.value as string
})
closeAddReaderModal()
}

const inputRef = useRef<HTMLInputElement>(null)

useEffect(() => {
if (data !== undefined) {
setReaders(data)
}
}, [data])

return (
<div>
<p className='text-lg text-gray-600'>リーダー中身</p>
<GeneralDivider label={label} />

<div className='flex justify-center'>
<div className='space-y-5'>
{readers.map(reader => (
<ReaderCard
key={reader.client_id}
clientId={reader.client_id}
name={reader.name}
onChangeState={() => {
refetch()
}}
/>
))}
</div>
</div>

<AddReaderModal>
<div className='space-y-10 rounded-lg bg-white px-8 py-10'>
<h1 className='text-center text-lg font-semibold'>カードリーダー追加</h1>
<input
type='text'
ref={inputRef}
className='rounded-md bg-gray-300 bg-transparent py-1 shadow-md outline-none'
/>

<div className='flex items-center justify-between px-3 py-3'>
<button onClick={addReader} className='rounded-xl bg-indigo-300 px-4 py-2'>
追加
</button>
<button
onClick={closeAddReaderModal}
className='rounded-xl bg-black px-4 py-2 text-white'
>
閉じる
</button>
</div>
</div>
</AddReaderModal>

<NewReaderModal>
<div className='space-y-10 rounded-lg bg-white px-8 py-10 text-center'>
<h1 className='text-center text-lg font-semibold'>カードリーダー追加完了</h1>
<p className='text-md text-center font-semibold'>新しいカードリーダーが追加されました</p>
<div className='space-y-3'>
<p className='rounded-lg bg-gray-300 px-3 py-1 text-start'>
リーダー名: {newReader?.name}
</p>
<p className='rounded-lg bg-gray-300 px-3 py-3 text-start'>
client_id: {newReader?.client_id}
</p>
<p className='rounded-lg bg-gray-300 px-3 py-3 text-start'>
client_token: {newReader?.client_token}
</p>
</div>

<button
onClick={closeNewReaderModal}
className='rounded-xl bg-black px-4 py-2 text-white'
>
閉じる
</button>
</div>
</NewReaderModal>

<Plus
className='fixed bottom-20 right-14 h-14 w-14 rounded-full bg-black p-2 text-white shadow-xl hover:cursor-pointer max-md:bottom-20 max-md:right-14'
onClick={openAddReaderModal}
/>
</div>
)
}
Expand Down
96 changes: 96 additions & 0 deletions src/components/ReaderCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import React, { useRef } from 'react'
import { Edit3, Trash2 } from 'react-feather'
import { useModal } from 'react-hooks-use-modal'
import { trpc } from '../utils/trpc'

type ReaderCardProps = {
clientId: string
name: string
onChangeState?: () => void
}

function ReaderCard({ clientId, name, onChangeState }: ReaderCardProps) {
const inputRef = useRef<HTMLInputElement>(null)
const renameMutation = trpc.reader.updateReaderName.useMutation({
onSuccess: onChangeState
})
const deleteMutation = trpc.reader.deleteReader.useMutation({
onSuccess: onChangeState
})

const [RenameReaderModal, openRenameModal, closeRenameModal] = useModal('__next', {
preventScroll: true
})

const [DeleteReaderModal, openDeleteModal, closeDeleteModal] = useModal('__next', {
preventScroll: true
})

const renameReader = () => {
renameMutation.mutate({
clientId: clientId,
updatedName: inputRef.current?.value as string
})
closeRenameModal()
}

const deleteReader = () => {
deleteMutation.mutate({
clientId: clientId
})
closeDeleteModal()
}

return (
<div className='space-y-7 rounded-xl bg-gray-600 px-16 py-14'>
<span className='text-xl font-semibold text-gray-200'>{name}</span>
<div className='flex items-center space-x-32'>
<Edit3 onClick={openRenameModal} className='h-6 w-6 text-gray-300 hover:cursor-pointer' />
<Trash2 onClick={openDeleteModal} className='h-6 w-6 text-gray-300 hover:cursor-pointer' />
</div>

<RenameReaderModal>
<div className='space-y-10 rounded-lg bg-white px-8 py-10'>
<h1 className='text-center text-lg font-semibold'>カードリーダー名変更</h1>
<input
type='text'
ref={inputRef}
defaultValue={name}
className='rounded-md bg-gray-300 bg-transparent py-1 shadow-md outline-none'
/>

<div className='flex items-center justify-between px-3 py-3'>
<button onClick={renameReader} className='rounded-xl bg-indigo-300 px-4 py-2'>
変更
</button>
<button onClick={closeRenameModal} className='rounded-xl bg-black px-4 py-2 text-white'>
閉じる
</button>
</div>
</div>
</RenameReaderModal>

<DeleteReaderModal>
<div className='space-y-6 rounded-lg bg-white px-8 py-10'>
<h1 className='text-center text-lg font-semibold'>カードリーダー削除</h1>
<p>下記のカードリーダーを削除します</p>
<div className='rounded-lg bg-gray-300 px-4 py-3'>
<p>clientId: {clientId}</p>
<p>名前: {name}</p>
</div>

<div className='flex items-center justify-between px-3 py-3'>
<button onClick={deleteReader} className='rounded-xl bg-red-500 px-4 py-2'>
削除
</button>
<button onClick={closeDeleteModal} className='rounded-xl bg-black px-4 py-2 text-white'>
閉じる
</button>
</div>
</div>
</DeleteReaderModal>
</div>
)
}

export default ReaderCard
2 changes: 1 addition & 1 deletion src/components/SettingMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function SettingMenu({
{bodyElement}
</div>
<div className='max-md:mb-5 md:mt-6 md:mb-10'>
<div className='flex flex-row items-center justify-center space-x-7 text-lg font-semibold decoration-2 underline-offset-8'>
<div className='flex flex-row items-center justify-center space-x-7 bg-white py-3 text-lg font-semibold decoration-2 underline-offset-8 max-md:fixed max-md:bottom-0 max-md:left-0 max-md:right-0 max-md:z-30'>
{isAdmin && (
<Link
href='/log'
Expand Down
33 changes: 33 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,11 @@ binary-extensions@^2.0.0:
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==

body-scroll-lock@^4.0.0-beta.0:
version "4.0.0-beta.0"
resolved "https://registry.yarnpkg.com/body-scroll-lock/-/body-scroll-lock-4.0.0-beta.0.tgz#4f78789d10e6388115c0460cd6d7d4dd2bbc4f7e"
integrity sha512-a7tP5+0Mw3YlUJcGAKUqIBkYYGlYxk2fnCasq/FUph1hadxlTRjF+gAcZksxANnaMnALjxEddmSi/H3OR8ugcQ==

brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
Expand Down Expand Up @@ -1125,6 +1130,21 @@ flatted@^3.1.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==

focus-trap-react@^10.0.2:
version "10.1.0"
resolved "https://registry.yarnpkg.com/focus-trap-react/-/focus-trap-react-10.1.0.tgz#7cfb5551b32c22b5e8496f8914609f37ec6c072f"
integrity sha512-mAUw9lrcZbMz/KZZdU55TuwHp5991hES7z7WKokopzIsRC5cTmbMUXRIhN7ZNPW4Mt7ULAH+gVjm0v4e2kN4/Q==
dependencies:
focus-trap "^7.3.1"
tabbable "^6.1.1"

focus-trap@^7.3.1:
version "7.3.1"
resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-7.3.1.tgz#417c98e5f1ab94e717d31f1bafa2da45dabcd65f"
integrity sha512-bX/u4FJ+F0Pp6b/8Q9W8Br/JaLJ7rrhOJAzai9JU8bh4BPdOjEATy4pxHcbBBxFjPN4d1oHy7/KqknEdOetm9w==
dependencies:
tabbable "^6.1.1"

fraction.js@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950"
Expand Down Expand Up @@ -2080,6 +2100,14 @@ react-feather@^2.0.10:
dependencies:
prop-types "^15.7.2"

react-hooks-use-modal@^3.3.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/react-hooks-use-modal/-/react-hooks-use-modal-3.3.1.tgz#8b0e4c8a08e9feeca1474a55da207f49be900920"
integrity sha512-YgVZHZVtfpIpYkfQjIFe1T6tIsawEWkBInAzO7oKfu9YBJyuThw+fy2uqqRBTuNmHBTZg9oAJIAFEvhapHRmGQ==
dependencies:
body-scroll-lock "^4.0.0-beta.0"
focus-trap-react "^10.0.2"

react-icons@^4.7.1:
version "4.7.1"
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.7.1.tgz#0f4b25a5694e6972677cb189d2a72eabea7a8345"
Expand Down Expand Up @@ -2316,6 +2344,11 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==

tabbable@^6.1.1:
version "6.1.1"
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.1.1.tgz#40cfead5ed11be49043f04436ef924c8890186a0"
integrity sha512-4kl5w+nCB44EVRdO0g/UGoOp3vlwgycUVtkk/7DPyeLZUCuNFFKCFG6/t/DgHLrUPHjrZg6s5tNm+56Q2B0xyg==

tailwindcss@^3.2.0:
version "3.2.4"
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.2.4.tgz#afe3477e7a19f3ceafb48e4b083e292ce0dc0250"
Expand Down