Skip to content

Commit

Permalink
Merge pull request #6972 from opengovsg/release_v6.96.0
Browse files Browse the repository at this point in the history
build: release v6.96.0
  • Loading branch information
KenLSM authored Dec 21, 2023
2 parents 56af23c + b0cdd4e commit 38e4a98
Show file tree
Hide file tree
Showing 157 changed files with 8,322 additions and 4,828 deletions.
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,32 @@ All notable changes to this project will be documented in this file. Dates are d

Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).

#### [v6.96.0](https://github.com/opengovsg/FormSG/compare/v6.96.0...v6.96.0)

- revert: "feat: Payments thank you page" [`#6973`](https://github.com/opengovsg/FormSG/pull/6973)

#### [v6.96.0](https://github.com/opengovsg/FormSG/compare/v6.95.0...v6.96.0)

> 21 December 2023

- feat: multi-respondent forms [`#6960`](https://github.com/opengovsg/FormSG/pull/6960)
- feat: Payments thank you page [`#6961`](https://github.com/opengovsg/FormSG/pull/6961)
- fix(deps): bump libphonenumber-js from 1.10.51 to 1.10.52 in /shared [`#6963`](https://github.com/opengovsg/FormSG/pull/6963)
- build: merge v6.95.0 into develop [`#6957`](https://github.com/opengovsg/FormSG/pull/6957)
- chore: use responses instead of results [`#6922`](https://github.com/opengovsg/FormSG/pull/6922)
- build: release v6.95.0 [`#6956`](https://github.com/opengovsg/FormSG/pull/6956)
- chore: bump version to v6.96.0 [`1195d9d`](https://github.com/opengovsg/FormSG/commit/1195d9db2f6ca396db832b07eb6c7dfb4290c159)

#### [v6.95.0](https://github.com/opengovsg/FormSG/compare/v6.94.0...v6.95.0)

> 11 December 2023

- fix: show error toast if error is not a network error [`#6950`](https://github.com/opengovsg/FormSG/pull/6950)
- fix: fix attachment file size check differences between FE and BE [`#6955`](https://github.com/opengovsg/FormSG/pull/6955)
- build(deps): [Snyk] Security upgrade @opengovsg/formsg-sdk from 0.10.0 to 0.11.0 [`#6951`](https://github.com/opengovsg/FormSG/pull/6951)
- build: merge release v6.94.0 into develop [`#6954`](https://github.com/opengovsg/FormSG/pull/6954)
- build: release v6.94.0 [`#6953`](https://github.com/opengovsg/FormSG/pull/6953)
- chore: bump version to v6.95.0 [`a805a92`](https://github.com/opengovsg/FormSG/commit/a805a92f4ec01c4e00ef8c6498e2a03826cdc5db)

#### [v6.94.0](https://github.com/opengovsg/FormSG/compare/v6.93.0...v6.94.0)

Expand Down
61 changes: 21 additions & 40 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "form-frontend",
"version": "6.95.0",
"version": "6.96.0",
"homepage": ".",
"private": true,
"dependencies": {
Expand All @@ -11,7 +11,7 @@
"@emotion/styled": "^11.6.0",
"@floating-ui/react-dom-interactions": "^0.9.3",
"@growthbook/growthbook-react": "^0.17.0",
"@opengovsg/formsg-sdk": "^0.11.0",
"@opengovsg/formsg-sdk": "^0.12.0-alpha.1",
"@stablelib/base64": "^1.0.1",
"@stripe/react-stripe-js": "^1.15.0",
"@stripe/stripe-js": "^1.44.1",
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/app/AppRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
ADMINFORM_USETEMPLATE_ROUTE,
BILLING_ROUTE,
DASHBOARD_ROUTE,
EDIT_SUBMISSION_PAGE_SUBROUTE,
LANDING_PAYMENTS_ROUTE,
LANDING_ROUTE,
LOGIN_CALLBACK_ROUTE,
Expand Down Expand Up @@ -145,6 +146,14 @@ export const AppRouter = (): JSX.Element => {
/>
}
/>
<Route
path={EDIT_SUBMISSION_PAGE_SUBROUTE}
element={
<ParamIdValidator
element={<PublicElement element={<PublicFormPage />} />}
/>
}
/>
</Route>
<Route
path={`${ADMINFORM_ROUTE}/:formId`}
Expand Down
20 changes: 20 additions & 0 deletions frontend/src/assets/icons/MultiParty.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export const MultiParty = (
props: React.SVGProps<SVGSVGElement>,
): JSX.Element => {
return (
<svg
width="40"
height="40"
viewBox="0 0 40 40"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M20.5732 10.032L18.9012 11.5921L18.8229 11.6652L18.9012 11.7383L19.715 12.4977L19.7833 12.5614L19.8515 12.4977L23.0984 9.46808L23.1768 9.39498L23.0985 9.32186L19.8515 6.29096L19.7833 6.22727L19.715 6.29094L18.9012 7.05031L18.8229 7.1234L18.9012 7.19651L20.5734 8.75793H15.5221C15.2037 5.65438 12.5816 3.2335 9.39403 3.2335C5.99166 3.2335 3.2335 5.99166 3.2335 9.39403C3.2335 12.7964 5.99166 15.5546 9.39403 15.5546C12.581 15.5546 15.2026 13.1346 15.5219 10.032H20.5732ZM10.0317 19.4264L11.5918 21.0985L11.6649 21.1768L11.738 21.0985L12.4974 20.2846L12.5611 20.2164L12.4974 20.1482L9.46778 16.9012L9.39468 16.8229L9.32156 16.9012L6.29066 20.1482L6.22698 20.2164L6.29065 20.2846L7.05001 21.0985L7.1231 21.1768L7.19622 21.0985L8.75763 19.4263V24.4778C5.65422 24.7964 3.2335 27.4184 3.2335 30.6059C3.2335 34.0082 5.99166 36.7664 9.39402 36.7664C12.7964 36.7664 15.5546 34.0082 15.5546 30.6059C15.5546 27.4188 13.1345 24.7971 10.0317 24.478V19.4264ZM29.9682 15.5219L29.9682 20.5735L28.4081 18.9014L28.335 18.8231L28.2619 18.9014L27.5025 19.7153L27.4388 19.7835L27.5025 19.8517L30.5321 23.0987L30.6052 23.177L30.6783 23.0987L33.7092 19.8517L33.7729 19.7835L33.7093 19.7153L32.9499 18.9014L32.8768 18.8231L32.8037 18.9014L31.2423 20.5736V15.5221C34.3457 15.2035 36.7664 12.5815 36.7664 9.39403C36.7664 5.99166 34.0082 3.2335 30.6059 3.2335C27.2035 3.2335 24.4453 5.99166 24.4453 9.39403C24.4453 12.5811 26.8654 15.2028 29.9682 15.5219ZM13.3809 9.39403C13.3809 11.5959 11.5959 13.3809 9.39403 13.3809C7.19214 13.3809 5.40716 11.5959 5.40716 9.39403C5.40716 7.19214 7.19214 5.40716 9.39403 5.40716C11.5959 5.40716 13.3809 7.19214 13.3809 9.39403ZM9.39402 26.619C11.5959 26.619 13.3809 28.404 13.3809 30.6059C13.3809 32.8078 11.5959 34.5927 9.39402 34.5927C7.19214 34.5927 5.40716 32.8078 5.40716 30.6059C5.40715 28.404 7.19214 26.619 9.39402 26.619ZM30.6059 13.3809C28.404 13.3809 26.619 11.5959 26.619 9.39403C26.619 7.19214 28.404 5.40716 30.6059 5.40716C32.8078 5.40716 34.5927 7.19214 34.5927 9.39403C34.5927 11.5959 32.8078 13.3809 30.6059 13.3809ZM34.3734 30.5266C34.3734 32.6514 32.6509 34.3739 30.5261 34.3739C28.4013 34.3739 26.6788 32.6514 26.6788 30.5266C26.6788 28.4017 28.4013 26.6792 30.5261 26.6792C32.6509 26.6792 34.3734 28.4017 34.3734 30.5266ZM30.5261 36.7668C33.9725 36.7668 36.7664 33.973 36.7664 30.5266C36.7664 27.0802 33.9725 24.2863 30.5261 24.2863C27.0797 24.2863 24.2859 27.0802 24.2859 30.5266C24.2859 33.973 27.0797 36.7668 30.5261 36.7668Z"
fill="#293044"
stroke="#445072"
stroke-width="0.2"
/>
</svg>
)
}
1 change: 1 addition & 0 deletions frontend/src/assets/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ export * from './BxsStar'
export * from './BxStar'
export * from './BxsXCircle'
export * from './BxX'
export * from './MultiParty'
export * from './PhHandsClapping'
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import { useCallback, useMemo, useRef } from 'react'
import { RegisterOptions, useForm } from 'react-hook-form'
import { BiUpload } from 'react-icons/bi'
import {
FormControl,
FormErrorMessage,
IconButton,
Input,
Skeleton,
Stack,
} from '@chakra-ui/react'

import { GUIDE_SECRET_KEY_LOSS } from '~constants/links'
import { useIsMobile } from '~hooks/useIsMobile'
import { isKeypairValid, SECRET_KEY_REGEX } from '~utils/secretKeyValidation'

import Button from '../Button'
import FormLabel from '../FormControl/FormLabel'
import Link from '../Link'

const SECRET_KEY_NAME = 'secretKey'

export type SecretKeyVerificationInputProps = {
publicKey: string | null
setSecretKey: (secretKey: string) => void
isLoading: boolean
description: string
isButtonFullWidth: boolean
showGuideLink: boolean
buttonText: string
prefillSecretKey?: string
}

interface SecretKeyFormInputs {
[SECRET_KEY_NAME]: string
}

export const SecretKeyVerificationInput = ({
publicKey,
setSecretKey,
isLoading,
description,
isButtonFullWidth,
showGuideLink,
buttonText,
prefillSecretKey,
}: SecretKeyVerificationInputProps) => {
const isMobile = useIsMobile()

const {
formState: { errors },
setError,
register,
setValue,
handleSubmit,
} = useForm<SecretKeyFormInputs>({
defaultValues: { secretKey: prefillSecretKey },
})

const fileUploadRef = useRef<HTMLInputElement | null>(null)

const secretKeyValidationRules: RegisterOptions = useMemo(() => {
return {
required: "Please enter the form's secret key",
validate: (secretKey: string) => {
// Should not see this error message.
if (!publicKey) return 'Unexpected form mode'

const isValid = isKeypairValid(publicKey, secretKey)
return isValid || 'The secret key provided is invalid'
},
}
}, [publicKey])

const handleVerifyKeypair = handleSubmit(({ secretKey }) => {
return setSecretKey(secretKey.trim())
})

const handleFileSelect = useCallback(
({ target }: React.ChangeEvent<HTMLInputElement>) => {
const file = target.files?.[0]
// Reset file input so the same file selected will trigger this onChange
// function.
if (fileUploadRef.current) {
fileUploadRef.current.value = ''
}

if (!file) return

const reader = new FileReader()
reader.onload = async (e) => {
if (!e.target) return
const text = e.target.result?.toString().trim()

if (!text || !SECRET_KEY_REGEX.test(text)) {
return setError(
SECRET_KEY_NAME,
{
type: 'invalidFile',
message: 'Selected file seems to be invalid',
},
{ shouldFocus: true },
)
}

setValue(SECRET_KEY_NAME, text, { shouldValidate: true })
}
reader.readAsText(file)
},
[setError, setValue],
)

return (
<form onSubmit={handleVerifyKeypair} noValidate>
{/* Hidden input field to trigger file selector, can be anywhere in the DOM */}
<Input
name="secretKeyFile"
ref={fileUploadRef}
type="file"
accept="text/plain"
onChange={handleFileSelect}
display="none"
/>
<FormControl isRequired isInvalid={!!errors.secretKey} mb="1rem">
<FormLabel description={description}>
Enter or upload Secret Key
</FormLabel>
<Stack direction="row" spacing="0.5rem">
<Skeleton isLoaded={!isLoading} w="100%">
<Input
isDisabled={isLoading}
{...register(SECRET_KEY_NAME, secretKeyValidationRules)}
/>
</Skeleton>
<Skeleton isLoaded={!isLoading}>
<IconButton
isDisabled={isLoading}
variant="outline"
aria-label="Pass secret key from file"
icon={<BiUpload />}
onClick={() => fileUploadRef.current?.click()}
/>
</Skeleton>
</Stack>
<FormErrorMessage>{errors.secretKey?.message}</FormErrorMessage>
</FormControl>
<Stack
spacing={{ base: '1.5rem', md: '2rem' }}
align="center"
direction={{ base: 'column', md: 'row' }}
mt="2rem"
>
<Button
isFullWidth={isMobile || isButtonFullWidth}
isDisabled={isLoading}
type="submit"
>
{buttonText}
</Button>
{showGuideLink && (
<Link variant="standalone" isExternal href={GUIDE_SECRET_KEY_LOSS}>
Can't find your Secret Key?
</Link>
)}
</Stack>
</form>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { SecretKeyVerificationInput as default } from './SecretKeyVerificationInput'
2 changes: 2 additions & 0 deletions frontend/src/constants/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ export const ACTIVE_ADMINFORM_RESULTS_ROUTE_REGEX = new RegExp(
`${ADMINFORM_ROUTE}/([a-fA-F0-9]{24})/${ADMINFORM_RESULTS_SUBROUTE}(/${RESULTS_FEEDBACK_SUBROUTE}|/${RESULTS_CHARTS_SUBROUTE})?/?`,
'i',
)

export const PAYMENT_PAGE_SUBROUTE = 'payment/:paymentId'
export const EDIT_SUBMISSION_PAGE_SUBROUTE = 'edit/:submissionId'

// Path for growthbook api proxy, set up on cloudflare workers. Worker script: https://github.com/opengovsg/formsg-private/pull/171.
export const GROWTHBOOK_API_HOST_PATH = '/api/v1/proxy/growthbook'
Loading

0 comments on commit 38e4a98

Please sign in to comment.