-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* Button * Reorganise files * Working scanner * Working scanner and types * Types * fixes * update error handling * Update EntitySearch.tsx --------- Co-authored-by: Andrew <vanbeekandrew@gmail.com> Co-authored-by: Tom Caiger <caigertom@gmail.com>
- Loading branch information
1 parent
84846fa
commit 2fa1912
Showing
8 changed files
with
291 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
150 changes: 150 additions & 0 deletions
150
packages/tupaia-web/src/features/QRCodeScanner/QRCodeScanner.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
/** | ||
* Tupaia | ||
* Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd | ||
*/ | ||
import React, { useState } from 'react'; | ||
import styled from 'styled-components'; | ||
import { Button, IconButton, SmallAlert } from '@tupaia/ui-components'; | ||
import { QrReader } from 'react-qr-reader'; | ||
import { get } from '../../api'; | ||
// This import is the actual type that QrReader uses | ||
import { Result } from '@zxing/library'; | ||
import { QRScanIcon } from './QRScanIcon'; | ||
import { ClickAwayListener, Typography } from '@material-ui/core'; | ||
import { Close } from '@material-ui/icons'; | ||
import { generatePath, useLocation, useNavigate, useParams } from 'react-router'; | ||
import { ROUTE_STRUCTURE } from '../../constants'; | ||
|
||
const QRScanButton = styled(Button).attrs({ | ||
startIcon: <QRScanIcon />, | ||
variant: 'text', | ||
})` | ||
background: ${({ theme }) => theme.palette.background.paper}; | ||
text-transform: none; | ||
font-size: 0.875rem; | ||
font-weight: 400; | ||
padding-inline: 0.5rem; | ||
white-space: nowrap; | ||
height: 100%; | ||
`; | ||
|
||
const ScannerWrapper = styled.div` | ||
position: fixed; | ||
top: 0; | ||
left: 0; | ||
height: 100vh; | ||
width: 100vw; | ||
z-index: 10; | ||
background: ${({ theme }) => theme.palette.background.paper}; | ||
padding-inline: 1.4rem; | ||
padding-block: 1.2rem; | ||
`; | ||
|
||
const CloseButton = styled(IconButton)` | ||
.MuiSvgIcon-root { | ||
font-size: 1rem; | ||
} | ||
padding: 0.5rem; | ||
`; | ||
|
||
const Header = styled.div` | ||
display: flex; | ||
justify-content: space-between; | ||
align-items: center; | ||
`; | ||
|
||
const Title = styled(Typography).attrs({ | ||
variant: 'h1', | ||
})` | ||
font-size: 0.75rem; | ||
font-weight: 500; | ||
`; | ||
|
||
export const QRCodeScanner = ({ onCloseEntitySearch }: { onCloseEntitySearch: () => void }) => { | ||
const { projectCode, dashboardName } = useParams(); | ||
const navigate = useNavigate(); | ||
const location = useLocation(); | ||
const [isQRScannerOpen, setIsQRScannerOpen] = useState(false); | ||
const [errorMessage, setErrorMessage] = useState<string | null>(null); | ||
|
||
const toggleQRScanner = () => { | ||
setIsQRScannerOpen(!isQRScannerOpen); | ||
setErrorMessage(null); | ||
}; | ||
|
||
const handleScan = async (data?: Result | null, error?: Error | null) => { | ||
if (error?.message) { | ||
setErrorMessage(error.message); | ||
} | ||
|
||
if (!data) { | ||
return; | ||
} | ||
|
||
const text = data.getText(); | ||
const entityId = text.replace('entity-', ''); | ||
let entityCode: string; | ||
|
||
try { | ||
const results = await get(`entities/${projectCode}/${projectCode}`, { | ||
params: { | ||
filter: { id: entityId }, | ||
fields: ['code'], | ||
}, | ||
}); | ||
const entity = results[0] ?? null; | ||
|
||
if (!entity) { | ||
setErrorMessage( | ||
'No matching entity found in selected project. Please try another QR code, or check your project selection.', | ||
); | ||
return; | ||
} | ||
entityCode = entity.code; | ||
// reset error message | ||
setErrorMessage(null); | ||
} catch (e) { | ||
setErrorMessage('Error fetching entity details. Please refresh the page and try again.'); | ||
return; | ||
} | ||
|
||
const path = generatePath(ROUTE_STRUCTURE, { | ||
projectCode, | ||
dashboardName, | ||
entityCode, | ||
}); | ||
|
||
// navigate to the entity page and close the scanner and entity search | ||
navigate({ | ||
...location, | ||
pathname: path, | ||
}); | ||
|
||
setIsQRScannerOpen(false); | ||
onCloseEntitySearch(); | ||
}; | ||
|
||
return ( | ||
<> | ||
<QRScanButton onClick={toggleQRScanner}>Scan ID</QRScanButton> | ||
{isQRScannerOpen && ( | ||
<ClickAwayListener onClickAway={toggleQRScanner}> | ||
<ScannerWrapper> | ||
<Header> | ||
<Title>Scan the location ID QR code using your camera</Title> | ||
<CloseButton onClick={toggleQRScanner}> | ||
<Close /> | ||
</CloseButton> | ||
</Header> | ||
{errorMessage && <SmallAlert severity="error">{errorMessage}</SmallAlert>} | ||
<QrReader | ||
// use the camera facing the environment (back camera) | ||
constraints={{ facingMode: 'environment' }} | ||
onResult={handleScan} | ||
/> | ||
</ScannerWrapper> | ||
</ClickAwayListener> | ||
)} | ||
</> | ||
); | ||
}; |
24 changes: 24 additions & 0 deletions
24
packages/tupaia-web/src/features/QRCodeScanner/QRScanIcon.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* | ||
* Tupaia | ||
* Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd | ||
*/ | ||
import React from 'react'; | ||
import { SvgIcon, SvgIconProps } from '@material-ui/core'; | ||
|
||
export const QRScanIcon = (props: SvgIconProps) => { | ||
return ( | ||
<SvgIcon | ||
{...props} | ||
width="20" | ||
height="20" | ||
viewBox="0 0 20 20" | ||
fill="none" | ||
xmlns="http://www.w3.org/2000/svg" | ||
> | ||
<path | ||
d="M4.92461 9.4373H9.36824V4.99367H4.92461V9.4373ZM5.82461 5.89355H8.46824V8.53717H5.82461V5.89355ZM14.9376 15.0065H10.1447V13.5928H11.0447V14.1067H12.0916V13.5928H12.9916V14.1067H14.0377V13.5928H14.9377L14.9377 15.0065H14.9376ZM11.0447 12.5213H10.1447V10.2139H13.3427V11.1139H11.0447V12.5213ZM17.2 4.65605V8.1438H16.3V4.65605C16.3 4.12924 15.871 3.70054 15.3437 3.70054H11.856V2.80054H15.3437C16.3672 2.80054 17.2 3.63292 17.2 4.65605ZM3.69999 8.1438H2.79999V4.65605C2.79999 3.6329 3.6328 2.80055 4.65624 2.80055H8.14399V3.70055H4.65624C4.12899 3.70055 3.69999 4.12911 3.69999 4.65606V8.1438ZM4.65624 16.2996H8.14399V17.1995H4.65624C3.6328 17.1995 2.79999 16.3669 2.79999 15.3433V11.8563H3.69999V15.3433C3.69999 15.8707 4.12899 16.2996 4.65624 16.2996ZM16.3 11.8563H17.2V15.3433C17.2 16.3669 16.3672 17.1995 15.3437 17.1995H11.856V16.2996H15.3437C15.871 16.2996 16.3 15.8705 16.3 15.3433V11.8563ZM4.92461 15.0064H9.36824V10.5629H4.92461V15.0064ZM5.82461 11.4628H8.46824V14.1064H5.82461V11.4628ZM14.9376 4.99355H10.494V9.43717H14.9376V4.99355ZM14.0376 8.53717H11.394V5.89342H14.0376V8.53717ZM11.7396 12.0712H14.9376V12.9712H11.7396V12.0712ZM14.9376 11.1775H14.0376V10.2136H14.9376V11.1775ZM6.71749 12.3558H7.57535V13.2136H6.71749V12.3558ZM6.71749 6.78637H7.57535V7.64424H6.71749V6.78637ZM13.1447 7.64424H12.2869V6.78637H13.1447V7.64424Z" | ||
fill="white" | ||
/> | ||
</SvgIcon> | ||
); | ||
}; |
21 changes: 21 additions & 0 deletions
21
packages/tupaia-web/src/features/QRCodeScanner/QrCodeButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/** | ||
* Tupaia | ||
* Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd | ||
*/ | ||
import React from 'react'; | ||
import styled from 'styled-components'; | ||
import { Button } from '@tupaia/ui-components'; | ||
import { QRScanIcon } from './QRScanIcon'; | ||
|
||
export const QrScanButton = styled(Button).attrs({ | ||
startIcon: <QRScanIcon />, | ||
variant: 'text', | ||
})` | ||
background: ${({ theme }) => theme.palette.background.paper}; | ||
text-transform: none; | ||
font-size: 0.875rem; | ||
font-weight: 400; | ||
padding-inline: 0.5rem; | ||
white-space: nowrap; | ||
height: 100%; | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
/** | ||
* Tupaia | ||
* Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd | ||
*/ | ||
export { QRCodeScanner } from './QRCodeScanner'; |
Oops, something went wrong.