You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

1 lines
23 KiB

{"version":3,"sources":["components/StatusChip.tsx","api/index.ts","pages/Dashboard.tsx","components/ScrollToTop.tsx","components/SessionPictures.tsx","pages/Session.tsx","App.tsx","reportWebVitals.ts","index.tsx"],"names":["Status","createClient","body","a","axios","post","res","data","client_id","getClient","id","get","startSession","clientId","timings","message","error","getSession","killSession","delete","restartSession","getStatus","status","Dashboard","history","useHistory","useState","setError","Form","useForm","form","handleSubmit","values","phone","length","name","email","parseInt","replace","push","Title","className","level","Text","onFinish","labelCol","span","wrapperCol","label","minLength","type","justify","danger","onClick","resetFields","htmlType","ScrollToTop","style","position","right","bottom","window","scrollTo","console","log","SessionPictures","urls","setUrls","activeUrl","setActiveUrl","JSON","parse","localStorage","getItem","focusPhotos","setFocusPhotos","useEffect","interval","setInterval","photos","clearInterval","closeModal","sort","b","split","localeCompare","u","filteredPhotos","filter","num","includes","visible","onOk","footer","onCancel","width","src","alt","align","display","margin","mode","allowClear","placeholder","defaultValue","value","onChange","v","setItem","stringify","map","val","Option","background","Math","floor","marginTop","title","colors","StatusChip","poll","setStatus","color","Session","props","match","params","client","setClient","active","setActive","lightTime","setLightTime","handleTimingUpdate","n","toString","handleStartSession","loading","light_time","handleRestartSession","handleExit","handleNuke","success","has_photos","disabled","onConfirm","e","target","min","max","step","process","App","path","component","exact","reportWebVitals","onPerfEntry","Function","then","getCLS","getFID","getFCP","getLCP","getTTFB","ReactDOM","render","document","getElementById"],"mappings":"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","file":"static/js/main.fd8c2650.chunk.js","sourcesContent":["import { Tag } from 'antd'\nimport { PresetColorType } from 'antd/lib/_util/colors'\nimport { useEffect, useState } from 'react'\nimport { getStatus } from '../api'\n\nexport enum Status {\n 'Standing By...',\n 'Warming Up...',\n 'Capturing Photo',\n 'Capturing Grid',\n 'Writing To Disk',\n 'Downloading!',\n}\n\nconst colors: Partial<PresetColorType>[] = [\n 'lime',\n 'gold',\n 'volcano',\n 'magenta',\n 'geekblue',\n]\n\ntype Props = {\n poll: boolean\n}\n\nexport const StatusChip = ({ poll }: Props) => {\n const [status, setStatus] = useState<Status>(Status['Standing By...'])\n\n useEffect(() => {\n const get = async () => {\n if (!poll) return\n const status = await getStatus()\n setStatus(status)\n }\n\n const interval = setInterval(get, 1000 / 4)\n\n return () => clearInterval(interval)\n }, [poll])\n\n return (\n <Tag color={colors[status]} style={{ display: 'flex' }}>\n <span style={{ margin: 'auto' }}>{Status[status]}</span>\n </Tag>\n )\n}\n","import { Client, Timings } from '../types'\nimport axios from 'axios'\nimport { message } from 'antd'\nimport { Status } from '../components/StatusChip'\n\nconst dev = process.env.NODE_ENV === 'development'\n\nif (dev) {\n const host = 'http://192.168.1.107:5000'\n axios.defaults.baseURL = host\n}\n\nconst mock = false\n\nexport const createClient = async (body: Omit<Client, 'has_photos'>) => {\n if (mock) return 'test'\n const res = await axios.post<{ client_id: string }>(`/api/clients`, body)\n return res.data.client_id\n}\n\nexport const getClient = async (id: string): Promise<Client> => {\n if (mock)\n return {\n name: 'Test Client',\n has_photos: false,\n email: 'test@test.test',\n phone: 1234567890,\n }\n const res = await axios.get<Client>(`/api/clients/${id}`)\n return res.data\n}\nexport const startSession = async (clientId: string, timings: Timings) => {\n try {\n const res = await axios.post(`/api/clients/${clientId}/session`, timings)\n return res.data\n } catch (err) {\n message.error('Something went wrong, check connection with the machine')\n return err\n }\n}\n\nexport const getSession = async (clientId: string) => {\n const res = await axios.get<{ photos: string[] }>(\n `/api/clients/${clientId}/session`,\n )\n return res.data // session data\n}\n\nexport const killSession = async (clientId: string) => {\n await axios.delete(`/api/clients/${clientId}/session`)\n}\n\nexport const restartSession = async (clientId: string, timings: Timings) => {\n await killSession(clientId)\n await startSession(clientId, timings)\n}\n\n// TOOD: Get status\n\nexport const getStatus = async (): Promise<Status> => {\n const res = await axios.get<{ status: Status }>('/api/status')\n return res.data.status\n}\n\n// Someday\n\nexport const getClients = async (): Promise<Client[]> => {\n const res = await axios.get<Client[]>(`/api/clients`)\n return res.data\n}\n\nexport const cleanup = () => {\n // send\n}\n","import { Button, Divider, Form, Input, message, Row, Typography } from 'antd'\nimport FormItem from 'antd/lib/form/FormItem'\nimport { Content } from 'antd/lib/layout/layout'\nimport React from 'react'\nimport { useState } from 'react'\nimport { useHistory } from 'react-router-dom'\nimport { createClient } from '../api'\n\ntype FormData = {\n name: string\n email: string\n phone: string\n}\n\nexport const Dashboard = () => {\n const history = useHistory()\n const [error, setError] = useState<string | null>(null)\n const [form] = Form.useForm<FormData>()\n\n const handleReset = () => {\n form.resetFields()\n }\n\n const handleSubmit = async (values: FormData) => {\n if (values.phone.length < 10) {\n // helpful message\n message.error('Check all fields!')\n setError('Phone number needs to be a length of at least 10')\n return\n }\n\n const client_id = await createClient({\n name: values.name,\n email: values.email,\n phone: parseInt(values.phone.replace(/\\D/g, '')),\n })\n\n history.push(`/sessions/${client_id}`)\n }\n\n return (\n <Content>\n <Typography.Title className=\"page-head\" level={3}>\n Dashboard\n </Typography.Title>\n <Typography.Text>\n Enter the name, email and phone number of the subject\n </Typography.Text>\n <Divider />\n <Form\n form={form}\n className=\"dashboard-form\"\n onFinish={handleSubmit}\n labelCol={{ span: 8 }}\n wrapperCol={{ span: 16 }}\n >\n <FormItem label=\"name\" name=\"name\">\n <Input minLength={3} />\n </FormItem>\n <FormItem label=\"email\" name=\"email\">\n <Input type=\"email\" />\n </FormItem>\n <FormItem label=\"phone\" name=\"phone\">\n <Input type=\"tel\" minLength={10} />\n </FormItem>\n <Row justify=\"space-between\">\n <Button danger onClick={handleReset}>\n Reset\n </Button>\n <Button htmlType=\"submit\" type=\"primary\">\n Start Session\n </Button>\n </Row>\n {error && <p className=\"error\">{error}</p>}\n </Form>\n </Content>\n )\n}\n","import { Button } from 'antd'\nimport React from 'react'\n\nexport const ScrollToTop = () => {\n const handleClick = () => {\n window.scrollTo(0, 0)\n console.log('')\n }\n\n return (\n <Button\n type=\"link\"\n style={{\n position: 'fixed',\n right: 20,\n bottom: 20,\n }}\n onClick={handleClick}\n >\n ⤴ Scroll To Top\n </Button>\n )\n}\n","import React, { useEffect, useState } from 'react'\nimport { Card, Modal, Row, Select, Typography } from 'antd'\nimport { getSession } from '../api'\nimport { ScrollToTop } from './ScrollToTop'\n\ntype Props = {\n clientId: string\n}\n\nexport const SessionPictures = ({ clientId }: Props) => {\n const [urls, setUrls] = useState<string[] | null>(null)\n const [activeUrl, setActiveUrl] = useState<string | null>(null)\n const [focusPhotos, setFocusPhotos] = useState<string[]>(\n JSON.parse(window.localStorage.getItem('focusPhotos') || '[]'),\n )\n\n useEffect(() => {\n const get = async () => {\n if (urls && urls.length >= 89 * 1) {\n return\n }\n\n const { photos } = await getSession(clientId)\n if (photos.length) setUrls(photos)\n }\n\n const interval = setInterval(get, 250)\n\n return () => clearInterval(interval)\n }, [clientId, urls])\n\n const closeModal = () => setActiveUrl(null)\n\n const host =\n process.env.NODE_ENV === 'development' ? 'http://192.168.1.107:5000' : ''\n\n if (!urls?.length) return null\n\n const photos = urls.sort((a, b) =>\n a.split('_')[0].localeCompare(b.split('_')[0]),\n )\n\n const u = urls.length / 89\n\n const handleSelect = (v: string[]) => {\n console.log('SEelcted', v)\n window.localStorage.setItem('focusPhotos', JSON.stringify(v))\n setFocusPhotos(v)\n }\n\n const filteredPhotos = photos.filter((name) => {\n const num = name.split('_')[0]\n return focusPhotos.includes(num)\n })\n\n return (\n <>\n <Modal\n visible={!!activeUrl}\n onOk={closeModal}\n footer={null}\n onCancel={closeModal}\n width=\"50%\"\n >\n <img\n width=\"100%\"\n onClick={closeModal}\n src={`${host}/output/${clientId}/${activeUrl}`}\n alt=\"large modal\"\n ></img>\n </Modal>\n <Row\n align=\"middle\"\n justify=\"space-around\"\n style={{ display: 'flex', width: '100%' }}\n >\n <Typography.Title style={{ margin: '0.5rem 1rem 0.7rem' }} level={3}>\n Session Pictures\n </Typography.Title>\n <Typography.Text>{urls.length}/ 89 loaded</Typography.Text>\n <Typography.Text>Select Featured Photos:</Typography.Text>\n\n <Select\n mode=\"multiple\"\n allowClear\n placeholder=\"Please select featured\"\n style={{ width: '35%' }}\n defaultValue={focusPhotos}\n value={focusPhotos}\n onChange={handleSelect}\n >\n {photos.map((name) => {\n const val = name.split('_')[0]\n return <Select.Option value={val}>{val}</Select.Option>\n })}\n </Select>\n </Row>\n\n <div className=\"loading-bar-container\">\n <div\n className=\"loading-bar\"\n style={{\n width: `${u * 100}%`,\n background: `hsl(${Math.floor(u * 120)}, 90%, 70%)`,\n }}\n ></div>\n </div>\n <div className=\"featured-photos\" style={{ marginTop: '2rem' }}>\n {filteredPhotos.map((src) => (\n <img\n onClick={() => setActiveUrl(src)}\n src={`${host}/output/${clientId}/${src}`}\n alt=\"lol\"\n />\n ))}\n </div>\n <div className=\"photo-wall\">\n {photos.map((src) => (\n <Card key={src} className=\"photo\" title={src.split('_')[0]}>\n <img\n onClick={() => setActiveUrl(src)}\n src={`${host}/output/${clientId}/${src}`}\n alt=\"lol\"\n />\n </Card>\n ))}\n </div>\n <ScrollToTop />\n </>\n )\n}\n","import React, { useEffect, useState } from 'react'\nimport { RouteComponentProps, useHistory } from 'react-router-dom'\nimport { getClient, killSession, restartSession, startSession } from '../api'\nimport { SessionPictures } from '../components/SessionPictures'\nimport { StatusChip } from '../components/StatusChip'\n\nimport {\n Button,\n Input,\n InputNumber,\n message,\n Popconfirm,\n Row,\n Typography,\n} from 'antd'\nimport { Content } from 'antd/lib/layout/layout'\nimport { Client } from '../types'\n\ntype Props = RouteComponentProps<{ clientId: string }>\n\nexport const Session = (props: Props) => {\n const history = useHistory()\n const { clientId } = props.match.params\n const [client, setClient] = useState<Client | null>(null)\n const [active, setActive] = useState(false)\n const [lightTime, setLightTime] = useState(\n parseInt(window.localStorage.getItem('lightTime') || '5000'),\n )\n\n const handleTimingUpdate = (n: number) => {\n window.localStorage.setItem('lightTime', n.toString())\n setLightTime(n)\n }\n\n const handleStartSession = async () => {\n message.loading('Photo sequence starting! Stand by...')\n await startSession(clientId, { light_time: lightTime })\n setActive(true)\n }\n\n const handleRestartSession = async () => {\n setActive(false)\n message.loading(\n 'Deleting photos & restarting capture sequence! Stand by...',\n )\n await restartSession(clientId, { light_time: lightTime })\n setActive(true)\n }\n\n const handleExit = async () => {\n history.push('/')\n }\n\n const handleNuke = async () => {\n await killSession(clientId)\n message.success('Photos Deleted! Going back to dashboard')\n history.push('/')\n }\n\n useEffect(() => {\n const get = async () => {\n const client = await getClient(clientId)\n setClient(client)\n if (client.has_photos) setActive(true)\n }\n\n get()\n }, [clientId])\n\n return (\n <Content>\n <Typography.Title className=\"page-head\" level={3}>\n Session View\n </Typography.Title>\n\n <Row className=\"client-info\">\n <Typography.Text>\n <strong>Name:</strong> {client?.name}\n </Typography.Text>\n <Typography.Text>\n <strong>Email:</strong> {client?.email}\n </Typography.Text>\n <Typography.Text>\n <strong>Phone:</strong> {client?.phone}\n </Typography.Text>\n </Row>\n <div className=\"toolbar\">\n <Row justify=\"center\" className=\"session-toolbar\">\n <Button key=\"finish\" onClick={handleExit}>\n Back To Dashboard\n </Button>\n <Button\n key=\"startsession\"\n disabled={active}\n type=\"primary\"\n onClick={handleStartSession}\n >\n Capture\n </Button>\n <Popconfirm\n disabled={!active}\n key=\"retry\"\n title=\"Re-capture set?\"\n onConfirm={handleRestartSession}\n >\n <Button type=\"default\" disabled={!active}>\n Retry Capture\n </Button>\n </Popconfirm>\n <Popconfirm\n key=\"nuke\"\n disabled={!active}\n title=\"Delete all photos and return to dashboard?\"\n onConfirm={handleNuke}\n >\n <Button danger disabled={!active}>\n Abort Session\n </Button>\n </Popconfirm>\n\n <StatusChip poll={true} />\n </Row>\n <Row className=\"session-toolbar\">\n <h3>Light Duration (ms)</h3>\n <InputNumber value={lightTime} onChange={handleTimingUpdate} />\n <Input\n className=\"slider\"\n type=\"range\"\n onChange={(e) => handleTimingUpdate(parseInt(e.target.value))}\n value={lightTime}\n min={500}\n max={10000}\n step={500}\n />\n </Row>\n </div>\n <Row className=\"controls\">\n {active && <SessionPictures clientId={clientId} />}\n </Row>\n </Content>\n )\n}\n","import React from 'react'\nimport './App.css'\n\nimport { BrowserRouter, Switch, Route } from 'react-router-dom'\nimport { Dashboard } from './pages/Dashboard'\nimport { Session } from './pages/Session'\n\nconsole.log('ENV', process.env.NODE_ENV)\n\nfunction App() {\n return (\n <BrowserRouter>\n <div className=\"App\">\n <Switch>\n <Route path=\"/sessions/:clientId\" component={Session} />\n <Route exact path=\"/\" component={Dashboard} />\n </Switch>\n </div>\n </BrowserRouter>\n )\n}\n\nexport default App\n","import { ReportHandler } from 'web-vitals';\n\nconst reportWebVitals = (onPerfEntry?: ReportHandler) => {\n if (onPerfEntry && onPerfEntry instanceof Function) {\n import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {\n getCLS(onPerfEntry);\n getFID(onPerfEntry);\n getFCP(onPerfEntry);\n getLCP(onPerfEntry);\n getTTFB(onPerfEntry);\n });\n }\n};\n\nexport default reportWebVitals;\n","import React from 'react'\nimport ReactDOM from 'react-dom'\nimport './index.css'\nimport 'antd/dist/antd.css'\nimport App from './App'\nimport reportWebVitals from './reportWebVitals'\n\nReactDOM.render(<App />, document.getElementById('root'))\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals()\n"],"sourceRoot":""}