-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
michaelthorpe
committed
Sep 14, 2023
1 parent
442987d
commit 33adaf2
Showing
11 changed files
with
381 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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 @@ | ||
dist/ | ||
node_modules/ | ||
package-lock.json | ||
pnpm-lock.yaml | ||
tsconfig.tsbuildinfo |
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,67 @@ | ||
Hods - Timeout-Modal | ||
==================== | ||
|
||
HODS timeout modal | ||
|
||
|
||
Using this package | ||
------------------ | ||
|
||
First install the package into your project: | ||
|
||
```shell | ||
npm install -S @hods/timeout-modal | ||
``` | ||
|
||
Then use it in your code as follows: | ||
|
||
```js | ||
import React, { createElement as h } from 'react'; | ||
import TimeoutModal from '@hods/timeout-modal'; | ||
|
||
export const MyComponent = props => ( | ||
<TimeoutModal | ||
// WRITEME | ||
/> | ||
); | ||
|
||
export default MyComponent; | ||
``` | ||
|
||
|
||
Working on this package | ||
----------------------- | ||
|
||
Before working on this package you must install its dependencies using | ||
the following command: | ||
|
||
```shell | ||
pnpm install | ||
``` | ||
|
||
|
||
### Testing | ||
|
||
Run the unit tests. | ||
|
||
```shell | ||
npm test | ||
``` | ||
|
||
|
||
### Building | ||
|
||
Build the package by compiling the TypeScript source code. | ||
|
||
```shell | ||
npm run build | ||
``` | ||
|
||
|
||
### Clean-up | ||
|
||
Remove any previously built files. | ||
|
||
```shell | ||
npm run clean | ||
``` |
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,58 @@ | ||
@import "@hods/sass-base"; | ||
@import "govuk-frontend/govuk/objects/_button-group"; | ||
@import "govuk-frontend/govuk/components/button/_button"; | ||
@import "govuk-frontend/govuk/core/_typography"; | ||
@import "govuk-frontend/govuk/core/_links"; | ||
|
||
.hods-timeout-modal { | ||
&__overlay { | ||
width: 100%; | ||
height: 100%; | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
background-color: rgba(0,0,0,0.8); | ||
z-index: 666; | ||
} | ||
&__content { | ||
min-width: 200px; | ||
max-width: 340px; | ||
@include govuk-responsive-padding(6); | ||
background-color: #fff; | ||
border: 3px solid #000000; | ||
|
||
h1 { | ||
@extend .govuk-heading-l; | ||
} | ||
|
||
p { | ||
@extend .govuk-body; | ||
} | ||
} | ||
&__buttons { | ||
@extend .govuk-button-group; | ||
@include govuk-responsive-margin(0, 'bottom'); | ||
|
||
button { | ||
@extend .govuk-button; | ||
|
||
@include govuk-media-query($from: tablet) { | ||
@include govuk-responsive-margin(0, 'bottom'); | ||
} | ||
} | ||
|
||
a { | ||
@extend .govuk-link; | ||
@include govuk-responsive-margin(0); | ||
|
||
@include govuk-media-query($from: tablet) { | ||
@include govuk-responsive-margin(3, 'left'); | ||
} | ||
} | ||
} | ||
&__timer { | ||
font-weight: $govuk-font-weight-bold; | ||
white-space: nowrap; | ||
} | ||
|
||
} |
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,15 @@ | ||
'use strict'; | ||
|
||
const baseConfig = require('../../jest.config.base'); | ||
|
||
const config = { | ||
...baseConfig, | ||
collectCoverageFrom: [ | ||
'<rootDir>/src/**.{ts,tsx}', | ||
], | ||
testMatch: [ | ||
'<rootDir>/spec/**.{ts,tsx}' | ||
] | ||
}; | ||
|
||
module.exports = config; |
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,53 @@ | ||
{ | ||
"name": "@hods/timeout-modal", | ||
"version": "0.4.0", | ||
"description": "HODS timeout modal", | ||
"main": "src/TimeoutModal.tsx", | ||
"sass": "assets/TimeoutModal.scss", | ||
"publishConfig": { | ||
"main": "dist/TimeoutModal.js", | ||
"typings": "dist/TimeoutModal.d.ts" | ||
}, | ||
"files": [ | ||
"/assets", | ||
"/dist" | ||
], | ||
"scripts": { | ||
"test": "NODE_OPTIONS=--experimental-vm-modules jest", | ||
"prepublishOnly": "npm run clean && npm run build", | ||
"build": "tsc", | ||
"clean": "rm -rf dist tsconfig.tsbuildinfo" | ||
}, | ||
"author": "Daniel A.C. Martin <[email protected]> (http://daniel-martin.co.uk/)", | ||
"license": "MIT", | ||
"keywords": [ | ||
"react-components" | ||
], | ||
"dependencies": { | ||
"@hods/sass-base": "workspace:^0.4.0", | ||
"@not-govuk/component-helpers": "^0.7.2", | ||
"govuk-frontend": "4.4.1" | ||
}, | ||
"peerDependencies": { | ||
"@not-govuk/docs-components": "^0.7.2", | ||
"@storybook/addon-docs": "^6.4.0", | ||
"react": "^16.9.55" | ||
}, | ||
"peerDependenciesMeta": { | ||
"@not-govuk/docs-components": { | ||
"optional": true | ||
}, | ||
"@storybook/addon-docs": { | ||
"optional": true | ||
} | ||
}, | ||
"devDependencies": { | ||
"@mdx-js/react": "1.6.22", | ||
"@not-govuk/component-test-helpers": "^0.7.2", | ||
"@types/react": "16.14.32", | ||
"jest": "29.2.2", | ||
"jest-environment-jsdom": "29.2.2", | ||
"ts-jest": "29.0.3", | ||
"typescript": "4.8.4" | ||
} | ||
} |
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,38 @@ | ||
import { Meta, Preview, Props, Story } from '@storybook/addon-docs'; | ||
import { TimeoutModal } from '../src/TimeoutModal'; | ||
import readMe from '../README.md'; | ||
|
||
<Meta | ||
title="Timeout Modal" | ||
component={ TimeoutModal } | ||
parameters={ { | ||
chromatic: { viewports: [640, 480] }, | ||
description: 'HODS timeout modal', | ||
jest: ['TimeoutModal'], | ||
notes: readMe | ||
} } | ||
/> | ||
|
||
# timeout-modal | ||
|
||
HODS timeout modal | ||
|
||
<Preview withToolbar> | ||
<Story name="TimeoutModal"> | ||
<TimeoutModal /> | ||
</Story> | ||
</Preview> | ||
|
||
<Props of={ TimeoutModal } /> | ||
|
||
|
||
## Stories | ||
### Standard | ||
|
||
A standard timeout-modal. | ||
|
||
<Preview> | ||
<Story name="Standard"> | ||
<TimeoutModal /> | ||
</Story> | ||
</Preview> |
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,23 @@ | ||
import { createElement as h } from 'react'; | ||
import { mount } from '@not-govuk/component-test-helpers'; | ||
import TimeoutModal from '../src/TimeoutModal'; | ||
|
||
describe('TimeoutModal', () => { | ||
const minimalProps = { | ||
}; | ||
|
||
describe('when given minimal valid props', () => { | ||
const component = mount(h(TimeoutModal, minimalProps, 'Child')); | ||
|
||
it('renders', () => undefined); | ||
}); | ||
|
||
describe('when given all valid props', () => { | ||
const props = { | ||
...minimalProps | ||
}; | ||
const component = mount(h(TimeoutModal, props, 'Child')); | ||
|
||
it('renders', () => undefined); | ||
}); | ||
}); |
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,47 @@ | ||
import { FC, createElement as h, useState } from 'react'; | ||
import { StandardProps, classBuilder } from '@not-govuk/component-helpers'; | ||
|
||
import '../assets/TimeoutModal.scss'; | ||
import { Timer } from './Timer'; | ||
|
||
export type TimeoutModalProps = StandardProps & { | ||
/** Determines whether the modal should be opend or closed */ | ||
isOpen: boolean, | ||
/** Starting value of the timeout timer in seconds */ | ||
timerDurationInSeconds: number, | ||
/** Function called when the user clicks the modal button */ | ||
onContinue: () => void, | ||
/** Function called when the user clicks the modal link */ | ||
onSignout: () => void, | ||
}; | ||
|
||
export const TimeoutModal: FC<TimeoutModalProps> = ({ | ||
children, | ||
classBlock, | ||
classModifiers, | ||
className, | ||
isOpen, | ||
timerDurationInSeconds = 300, | ||
onContinue, | ||
onSignout, | ||
...attrs | ||
}) => { | ||
const classes = classBuilder('hods-timeout-modal', classBlock, classModifiers, className); | ||
|
||
return ( | ||
<div {...attrs} className={classes('overlay')}> | ||
<div role='dialog' aria-labelledby='modalTitle' aria-describedby='modalContent' className={classes('content')}> | ||
<h1 id='modalTitle'>You will be signed out soon</h1> | ||
<p id='modalContent' aria-live='polite'>To protect your information, you will be signed out in <Timer className={classes('timer')} timerFrom={timerDurationInSeconds}/>.</p> | ||
<div className={classes('buttons')}> | ||
<button role='button' onClick={onContinue}>Continue on this page</button> | ||
<a role='link' onClick={onSignout}>Sign out</a> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
TimeoutModal.displayName = 'TimeoutModal'; | ||
|
||
export default TimeoutModal; |
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,53 @@ | ||
import { FC, createElement as h, useState, useEffect } from 'react'; | ||
import { StandardProps } from '@not-govuk/component-helpers'; | ||
|
||
export type TimerProps = StandardProps & { | ||
/** Timeout starting value in seconds */ | ||
timerFrom: number | ||
}; | ||
|
||
export const Timer: FC<TimerProps> = ({ | ||
timerFrom, | ||
...attrs | ||
}) => { | ||
const [runTimer, setRunTimer] = useState(true) | ||
const [timer, setTimer] = useState(timerFrom); | ||
const [formattedTimer, setFormattedTimer] = useState(Math.floor(timer / 60)); | ||
|
||
useEffect(() => { | ||
let interval; | ||
if(runTimer) { | ||
interval = setInterval(() => { | ||
setTimer((timer) => timer - 1); | ||
}, 1000); | ||
} else { | ||
clearInterval(interval); | ||
} | ||
return () => clearInterval(interval); | ||
}, [runTimer]) | ||
|
||
useEffect(() => { | ||
if(timer > 60) { | ||
if(timer % 60 == 0) { | ||
setFormattedTimer(Math.round(timer / 60)); | ||
} | ||
} else { | ||
if([60,40,20,0].includes(timer)) { | ||
setFormattedTimer(timer); | ||
if(timer == 0) { | ||
setRunTimer(false); | ||
} | ||
} | ||
} | ||
}, [timer]) | ||
|
||
useEffect(() => { | ||
return () => { | ||
setRunTimer(false); | ||
}; | ||
}, []); | ||
|
||
return ( | ||
<span {...attrs}>{formattedTimer} {timer <= 60 ? "seconds" : formattedTimer == 1 ? "minute" : "minutes"}</span> | ||
); | ||
}; |
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,14 @@ | ||
{ | ||
"extends": "../../tsconfig.build.json", | ||
"compilerOptions": { | ||
"outDir": "dist", | ||
"rootDir": "src" | ||
}, | ||
"include": [ | ||
"src" | ||
], | ||
"exclude": [ | ||
"dist", | ||
"node_modules" | ||
] | ||
} |
33adaf2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚀 Deployed on https://6502fcef474b2c604366a3d6--hods.netlify.app