186 lines
7.9 KiB
TypeScript
186 lines
7.9 KiB
TypeScript
import React from 'react'
|
||
import axios from 'axios'
|
||
import { Head, usePage } from '@inertiajs/react'
|
||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||
import {
|
||
faArrowLeft,
|
||
faQuestionCircle,
|
||
faBoxOpen,
|
||
faClipboardList,
|
||
faCubes,
|
||
faPlus,
|
||
} from '@fortawesome/free-solid-svg-icons'
|
||
import { toast, Toaster } from 'react-hot-toast'
|
||
|
||
import Tile from '../Components/Tile'
|
||
import TileLayout from '../Components/TileLayout'
|
||
import ModalPDA from '../Components/ModalPDA'
|
||
|
||
// your extracted modal forms:
|
||
import SetStockModal from '../Components/modals/SetStockModal'
|
||
import OtherReplacementModal from '../Components/modals/OtherReplacementModal'
|
||
import CountStockModal from '../Components/modals/CountStockModal'
|
||
|
||
type Role = 'Expedice' | 'Skladnik'
|
||
|
||
// actions per role
|
||
const roleActions: Record<Role, string[]> = {
|
||
Expedice: ['stockSectionScanned', 'labelScanned'],
|
||
Skladnik: ['batchScan', 'stockScan'],
|
||
}
|
||
|
||
// configuration for each tile: either opens a modal (modalKey),
|
||
// or performs an API call (onClick)
|
||
type TileConfig = {
|
||
title: string
|
||
icon: any
|
||
modalKey?: ModalKey
|
||
onClick?: () => void
|
||
}
|
||
|
||
const tilesConfig: Record<Role, Record<string, TileConfig[]>> = {
|
||
Expedice: {
|
||
stockSectionScanned: [
|
||
{ title: 'Not Present', icon: faBoxOpen, onClick: () => toast('Not Present clicked') },
|
||
{ title: 'Na pozici je jiny ovladac', icon: faBoxOpen, onClick: () => toast('Not Present clicked') },
|
||
{
|
||
title: 'Present but Shouldn’t',
|
||
icon: faClipboardList,
|
||
onClick: async () => {
|
||
// example direct axios call
|
||
try {
|
||
await axios.post('/api/presence-error', {}, { withCredentials: true })
|
||
toast.success('Reported!')
|
||
} catch {
|
||
toast.error('Failed to report')
|
||
}
|
||
},
|
||
},
|
||
{ title: 'Other Replacement (na test/one time)', icon: faPlus, modalKey: 'otherReplacement' },
|
||
{ title: 'Pridej vazbu na jiny ovladac', icon: faPlus, onClick: () => toast('Batch Info clicked') },
|
||
{ title: 'Pridej docasnou vazbu (nez prijde jine zbozi, i casove omezene, nejnizsi priorita)', icon: faPlus, onClick: () => toast('Batch Info clicked') },
|
||
{ title: 'Doplnit zbozi / dej vic kusu', icon: faPlus, onClick: () => toast('Batch Info clicked') },
|
||
{ title: 'Report - chci zmenit pozici(bliz / dal od expedice)', icon: faPlus, onClick: () => toast('Batch Info clicked') },
|
||
{ title: 'Pultovy prodej', icon: faPlus, onClick: () => toast('- naskenuju na webu / naskenuju na skladovem miste, obj. se udela automaticky, zakaznik si muze v rohu na PC vyplnit osobni udaje na special formulari - pak customera prida obsluha do obj') },
|
||
],
|
||
labelScanned: [
|
||
{ title: 'Info', icon: faClipboardList, onClick: () => toast('Batch Info clicked') },
|
||
]
|
||
},
|
||
Skladnik: {
|
||
batchScan: [
|
||
{ title: 'Batch Info', icon: faClipboardList, onClick: () => toast('Batch Info clicked') },
|
||
{ title: 'Set Stock', icon: faCubes, modalKey: 'setStock' },
|
||
{ title: 'Count Stock', icon: faPlus, modalKey: 'countStock' },
|
||
{ title: 'Stitkovani (male stitky)', icon: faClipboardList, onClick: () => toast('Stitkovani (male stitky)') },
|
||
{ title: 'Batch Info', icon: faClipboardList, onClick: () => toast('Batch Info clicked') },
|
||
{ title: 'Tisk QR kod na krabice', icon: faClipboardList, onClick: () => toast('Batch Info clicked') },
|
||
],
|
||
stockScan: [
|
||
{ title: 'Info', icon: faClipboardList, onClick: () => toast('Batch Info clicked') },
|
||
{ title: 'Zmena skladoveho mista (i presun jen casti kusu)', icon: faClipboardList, onClick: () => toast('Batch Info clicked') },
|
||
{ title: 'Uprava skladoveho mista (mene sekci, apod)', icon: faClipboardList, onClick: () => toast('Batch Info clicked') },
|
||
{ title: 'Zmena poctu', icon: faClipboardList, onClick: () => toast('Batch Info clicked') },
|
||
{ title: 'Discard (odebrat ze skladoveho mista / posilame zpet)', icon: faClipboardList, onClick: () => toast('Batch Info clicked') },
|
||
],
|
||
others: [
|
||
{ title: 'Nove skladove misto', icon: faClipboardList, onClick: () => toast('Batch Info clicked') },
|
||
]
|
||
},
|
||
}
|
||
|
||
type ModalKey = 'setStock' | 'otherReplacement' | 'countStock' | null
|
||
|
||
export default function PdaView() {
|
||
const {
|
||
auth: { user },
|
||
} = usePage<{ auth: { user: { role: string } } }>().props
|
||
|
||
const [role, setRole] = React.useState<Role>(
|
||
user.role === 'admin' ? 'Expedice' : (user.role as Role)
|
||
)
|
||
const [action, setAction] = React.useState<string>('')
|
||
const [activeModal, setActiveModal] = React.useState<ModalKey>(null)
|
||
|
||
const isAdmin = true
|
||
// const isAdmin = user.role === 'admin'
|
||
const tabs: Role[] = ['Expedice', 'Skladnik']
|
||
|
||
const closeModal = () => setActiveModal(null)
|
||
|
||
return (
|
||
<>
|
||
<Head title="PDA View" />
|
||
|
||
{/* Top bar */}
|
||
<div className="flex justify-between items-center bg-base-100 p-4 shadow">
|
||
|
||
<a className="link" href={route('dashboard')}><FontAwesomeIcon icon={faArrowLeft} /> Back</a>
|
||
<button className="btn btn-ghost">
|
||
<FontAwesomeIcon icon={faQuestionCircle} /> Help
|
||
</button>
|
||
</div>
|
||
|
||
{/* Admin tabs */}
|
||
{isAdmin && (
|
||
<div className="tabs justify-center bg-base-100">
|
||
{tabs.map((r) => (
|
||
<button
|
||
key={r}
|
||
className={`tab ${role === r ? 'tab-active' : ''}`}
|
||
onClick={() => {
|
||
setRole(r)
|
||
setAction('')
|
||
}}
|
||
>
|
||
{r}
|
||
</button>
|
||
))}
|
||
</div>
|
||
)}
|
||
|
||
{/* Action selectors */}
|
||
<div className="flex justify-center space-x-4 space-y-4 sm:space-y-0 p-4 sm:flex-nowrap flex-wrap">
|
||
{[...(roleActions[role] || []), 'clear'].map((act) => (
|
||
<button
|
||
key={act}
|
||
className="btn btn-outline"
|
||
onClick={() => {
|
||
const newAct = act === 'clear' ? '' : act
|
||
setAction(newAct)
|
||
toast(`Action set to ${newAct || 'none'}`)
|
||
}}
|
||
>
|
||
{act === 'clear' ? 'Clear Action' : act}
|
||
</button>
|
||
))}
|
||
</div>
|
||
|
||
{/* Tiles */}
|
||
<TileLayout>
|
||
{action &&
|
||
(tilesConfig[role][action] || []).map(({ title, icon, onClick, modalKey }) => (
|
||
<Tile
|
||
key={title}
|
||
title={title}
|
||
icon={icon}
|
||
onClick={() => {
|
||
if (modalKey) setActiveModal(modalKey)
|
||
else if (onClick) onClick()
|
||
}}
|
||
/>
|
||
))}
|
||
</TileLayout>
|
||
|
||
{/* Single Modal */}
|
||
<ModalPDA isOpen={activeModal !== null} onClose={closeModal}>
|
||
{activeModal === 'setStock' && <SetStockModal onClose={closeModal} />}
|
||
{activeModal === 'otherReplacement' && <OtherReplacementModal onClose={closeModal} />}
|
||
{activeModal === 'countStock' && <CountStockModal onClose={closeModal} />}
|
||
</ModalPDA>
|
||
|
||
<Toaster position="top-right" />
|
||
</>
|
||
)
|
||
}
|