From cc65d85806b57ac271deef7e0fc31df44935c80a Mon Sep 17 00:00:00 2001 From: en Date: Fri, 7 Mar 2025 11:42:09 +0000 Subject: [PATCH 01/10] refactor(styles): update css for other marks during sign --- src/components/PDFView/style.module.scss | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/PDFView/style.module.scss b/src/components/PDFView/style.module.scss index 61983d7..92c044e 100644 --- a/src/components/PDFView/style.module.scss +++ b/src/components/PDFView/style.module.scss @@ -8,6 +8,4 @@ position: absolute; z-index: 40; display: flex; - justify-content: center; - align-items: center; } -- 2.43.0 From 8e23a2d8a1c05a760f0233db49a3e0c1ccc2af38 Mon Sep 17 00:00:00 2001 From: en Date: Fri, 7 Mar 2025 11:43:01 +0000 Subject: [PATCH 02/10] refactor: remove custom sigit cache page and links --- src/pages/settings/Settings.tsx | 7 ------- src/routes/index.tsx | 1 - 2 files changed, 8 deletions(-) diff --git a/src/pages/settings/Settings.tsx b/src/pages/settings/Settings.tsx index 5acdd9c..1382bc1 100644 --- a/src/pages/settings/Settings.tsx +++ b/src/pages/settings/Settings.tsx @@ -1,6 +1,5 @@ import AccountCircleIcon from '@mui/icons-material/AccountCircle' import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos' -import CachedIcon from '@mui/icons-material/Cached' import RouterIcon from '@mui/icons-material/Router' import { ListItem, useTheme } from '@mui/material' import List from '@mui/material/List' @@ -74,12 +73,6 @@ export const SettingsPage = () => { {listItem('Relays')} - - - - - {listItem('Local Cache')} - {loginMethod === LoginMethod.nostrLogin && ( diff --git a/src/routes/index.tsx b/src/routes/index.tsx index f3580f9..f514e78 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -6,7 +6,6 @@ export const appPrivateRoutes = { sign: '/sign', settings: '/settings', profileSettings: '/settings/profile/:npub', - cacheSettings: '/settings/cache', relays: '/settings/relays', nostrLogin: '/settings/nostrLogin' } -- 2.43.0 From cc681af11a34619ce6c41f6316b4fe9e831ff6c2 Mon Sep 17 00:00:00 2001 From: en Date: Fri, 7 Mar 2025 12:15:26 +0000 Subject: [PATCH 03/10] feat(marks): add full name --- .../MarkTypeStrategy/FullName/Input.tsx | 20 ++++++ .../MarkTypeStrategy/FullName/index.tsx | 7 ++ .../MarkTypeStrategy/MarkStrategy.tsx | 4 +- src/hooks/useLocalStorage.ts | 64 +++++++++++++++++++ src/utils/localStorage.ts | 44 +++++++++++++ src/utils/mark.ts | 3 +- 6 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 src/components/MarkTypeStrategy/FullName/Input.tsx create mode 100644 src/components/MarkTypeStrategy/FullName/index.tsx create mode 100644 src/hooks/useLocalStorage.ts diff --git a/src/components/MarkTypeStrategy/FullName/Input.tsx b/src/components/MarkTypeStrategy/FullName/Input.tsx new file mode 100644 index 0000000..7b63ae6 --- /dev/null +++ b/src/components/MarkTypeStrategy/FullName/Input.tsx @@ -0,0 +1,20 @@ +import { useDidMount } from '../../../hooks' +import { useLocalStorage } from '../../../hooks/useLocalStorage' +import { MarkInputProps } from '../MarkStrategy' +import { MarkInputText } from '../Text/Input' + +export const MarkInputFullName = (props: MarkInputProps) => { + const [fullName, setFullName] = useLocalStorage('mark-fullname', '') + useDidMount(() => { + props.handler(fullName) + }) + return MarkInputText({ + ...props, + placeholder: 'Full Name', + value: fullName, + handler: (value) => { + setFullName(value) + props.handler(value) + } + }) +} diff --git a/src/components/MarkTypeStrategy/FullName/index.tsx b/src/components/MarkTypeStrategy/FullName/index.tsx new file mode 100644 index 0000000..1574c42 --- /dev/null +++ b/src/components/MarkTypeStrategy/FullName/index.tsx @@ -0,0 +1,7 @@ +import { MarkStrategy } from '../MarkStrategy' +import { MarkInputFullName } from './Input' + +export const FullNameStrategy: MarkStrategy = { + input: MarkInputFullName, + render: ({ value }) => <>{value} +} diff --git a/src/components/MarkTypeStrategy/MarkStrategy.tsx b/src/components/MarkTypeStrategy/MarkStrategy.tsx index 562302e..f842220 100644 --- a/src/components/MarkTypeStrategy/MarkStrategy.tsx +++ b/src/components/MarkTypeStrategy/MarkStrategy.tsx @@ -2,6 +2,7 @@ import { MarkType } from '../../types/drawing' import { CurrentUserMark, Mark } from '../../types/mark' import { TextStrategy } from './Text' import { SignatureStrategy } from './Signature' +import { FullNameStrategy } from './FullName' export interface MarkInputProps { value: string @@ -28,5 +29,6 @@ export type MarkStrategies = { export const MARK_TYPE_CONFIG: MarkStrategies = { [MarkType.TEXT]: TextStrategy, - [MarkType.SIGNATURE]: SignatureStrategy + [MarkType.SIGNATURE]: SignatureStrategy, + [MarkType.FULLNAME]: FullNameStrategy } diff --git a/src/hooks/useLocalStorage.ts b/src/hooks/useLocalStorage.ts new file mode 100644 index 0000000..ec6c9cb --- /dev/null +++ b/src/hooks/useLocalStorage.ts @@ -0,0 +1,64 @@ +import React, { useMemo } from 'react' +import { + getLocalStorageItem, + mergeWithInitialValue, + removeLocalStorageItem, + setLocalStorageItem +} from '../utils' + +const useLocalStorageSubscribe = (callback: () => void) => { + window.addEventListener('storage', callback) + return () => window.removeEventListener('storage', callback) +} + +export function useLocalStorage( + key: string, + initialValue: T +): [T, React.Dispatch>] { + const getSnapshot = () => { + // Get the stored value + const storedValue = getLocalStorageItem(key, initialValue) + + // Parse the value + const parsedStoredValue = JSON.parse(storedValue) + + // Merge the default and the stored in case some of the required fields are missing + return JSON.stringify( + mergeWithInitialValue(parsedStoredValue, initialValue) + ) + } + + const data = React.useSyncExternalStore(useLocalStorageSubscribe, getSnapshot) + + const setState: React.Dispatch> = React.useCallback( + (v: React.SetStateAction) => { + try { + const nextState = + typeof v === 'function' + ? (v as (prevState: T) => T)(JSON.parse(data)) + : v + + if (nextState === undefined || nextState === null) { + removeLocalStorageItem(key) + } else { + setLocalStorageItem(key, JSON.stringify(nextState)) + } + } catch (e) { + console.warn(e) + } + }, + [data, key] + ) + + React.useEffect(() => { + // Set local storage only when it's empty + const data = window.localStorage.getItem(key) + if (data === null) { + setLocalStorageItem(key, JSON.stringify(initialValue)) + } + }, [key, initialValue]) + + const memoized = useMemo(() => JSON.parse(data) as T, [data]) + + return [memoized, setState] +} diff --git a/src/utils/localStorage.ts b/src/utils/localStorage.ts index 8196e35..b0eb381 100644 --- a/src/utils/localStorage.ts +++ b/src/utils/localStorage.ts @@ -42,3 +42,47 @@ export const clear = () => { clearAuthToken() clearState() } + +export function mergeWithInitialValue(storedValue: T, initialValue: T): T { + if ( + !Array.isArray(storedValue) && + typeof storedValue === 'object' && + storedValue !== null + ) { + return { ...initialValue, ...storedValue } + } + return storedValue +} + +export function getLocalStorageItem(key: string, defaultValue: T): string { + try { + const data = window.localStorage.getItem(key) + if (data === null) return JSON.stringify(defaultValue) + return data + } catch (err) { + console.error(`Error while fetching local storage value: `, err) + return JSON.stringify(defaultValue) + } +} + +export function setLocalStorageItem(key: string, value: string) { + try { + window.localStorage.setItem(key, value) + dispatchLocalStorageEvent(key, value) + } catch (err) { + console.error(`Error while saving local storage value: `, err) + } +} + +export function removeLocalStorageItem(key: string) { + try { + window.localStorage.removeItem(key) + dispatchLocalStorageEvent(key, null) + } catch (err) { + console.error(`Error while deleting local storage value: `, err) + } +} + +function dispatchLocalStorageEvent(key: string, newValue: string | null) { + window.dispatchEvent(new StorageEvent('storage', { key, newValue })) +} diff --git a/src/utils/mark.ts b/src/utils/mark.ts index 1868403..319371c 100644 --- a/src/utils/mark.ts +++ b/src/utils/mark.ts @@ -171,8 +171,7 @@ export const DEFAULT_TOOLBOX: DrawTool[] = [ { identifier: MarkType.FULLNAME, icon: faIdCard, - label: 'Full Name', - isComingSoon: true + label: 'Full Name' }, { identifier: MarkType.JOBTITLE, -- 2.43.0 From c8f0d135f13dfea86068f7efb6c4c7152b299085 Mon Sep 17 00:00:00 2001 From: en Date: Fri, 7 Mar 2025 12:47:55 +0000 Subject: [PATCH 04/10] feat(marks): add job title and datetime --- .../MarkTypeStrategy/DateTime/Input.tsx | 25 +++++++++++++++++++ .../MarkTypeStrategy/DateTime/index.tsx | 7 ++++++ .../MarkTypeStrategy/JobTitle/Input.tsx | 20 +++++++++++++++ .../MarkTypeStrategy/JobTitle/index.tsx | 7 ++++++ .../MarkTypeStrategy/MarkStrategy.tsx | 6 ++++- src/utils/mark.ts | 6 ++--- 6 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 src/components/MarkTypeStrategy/DateTime/Input.tsx create mode 100644 src/components/MarkTypeStrategy/DateTime/index.tsx create mode 100644 src/components/MarkTypeStrategy/JobTitle/Input.tsx create mode 100644 src/components/MarkTypeStrategy/JobTitle/index.tsx diff --git a/src/components/MarkTypeStrategy/DateTime/Input.tsx b/src/components/MarkTypeStrategy/DateTime/Input.tsx new file mode 100644 index 0000000..fa68438 --- /dev/null +++ b/src/components/MarkTypeStrategy/DateTime/Input.tsx @@ -0,0 +1,25 @@ +import { MarkInputProps } from '../MarkStrategy' +import styles from '../../MarkFormField/style.module.scss' +import { useEffect, useRef } from 'react' + +export const MarkInputDateTime = ({ handler, placeholder }: MarkInputProps) => { + const ref = useRef(null) + useEffect(() => { + if (ref.current) { + ref.current.value = new Date().toISOString().slice(0, 16) + if (ref.current.valueAsDate) { + handler(ref.current.valueAsDate.toUTCString()) + } + } + }, [handler]) + return ( + + ) +} diff --git a/src/components/MarkTypeStrategy/DateTime/index.tsx b/src/components/MarkTypeStrategy/DateTime/index.tsx new file mode 100644 index 0000000..1892d49 --- /dev/null +++ b/src/components/MarkTypeStrategy/DateTime/index.tsx @@ -0,0 +1,7 @@ +import { MarkStrategy } from '../MarkStrategy' +import { MarkInputDateTime } from './Input' + +export const DateTimeStrategy: MarkStrategy = { + input: MarkInputDateTime, + render: ({ value }) => <>{value} +} diff --git a/src/components/MarkTypeStrategy/JobTitle/Input.tsx b/src/components/MarkTypeStrategy/JobTitle/Input.tsx new file mode 100644 index 0000000..47d2969 --- /dev/null +++ b/src/components/MarkTypeStrategy/JobTitle/Input.tsx @@ -0,0 +1,20 @@ +import { useDidMount } from '../../../hooks' +import { useLocalStorage } from '../../../hooks/useLocalStorage' +import { MarkInputProps } from '../MarkStrategy' +import { MarkInputText } from '../Text/Input' + +export const MarkInputJobTitle = (props: MarkInputProps) => { + const [jobTitle, setjobTitle] = useLocalStorage('mark-jobtitle', '') + useDidMount(() => { + props.handler(jobTitle) + }) + return MarkInputText({ + ...props, + placeholder: 'Job Title', + value: jobTitle, + handler: (value) => { + setjobTitle(value) + props.handler(value) + } + }) +} diff --git a/src/components/MarkTypeStrategy/JobTitle/index.tsx b/src/components/MarkTypeStrategy/JobTitle/index.tsx new file mode 100644 index 0000000..11f5d60 --- /dev/null +++ b/src/components/MarkTypeStrategy/JobTitle/index.tsx @@ -0,0 +1,7 @@ +import { MarkStrategy } from '../MarkStrategy' +import { MarkInputJobTitle } from './Input' + +export const JobTitleStrategy: MarkStrategy = { + input: MarkInputJobTitle, + render: ({ value }) => <>{value} +} diff --git a/src/components/MarkTypeStrategy/MarkStrategy.tsx b/src/components/MarkTypeStrategy/MarkStrategy.tsx index f842220..0ca0ebc 100644 --- a/src/components/MarkTypeStrategy/MarkStrategy.tsx +++ b/src/components/MarkTypeStrategy/MarkStrategy.tsx @@ -3,6 +3,8 @@ import { CurrentUserMark, Mark } from '../../types/mark' import { TextStrategy } from './Text' import { SignatureStrategy } from './Signature' import { FullNameStrategy } from './FullName' +import { JobTitleStrategy } from './JobTitle' +import { DateTimeStrategy } from './DateTime' export interface MarkInputProps { value: string @@ -30,5 +32,7 @@ export type MarkStrategies = { export const MARK_TYPE_CONFIG: MarkStrategies = { [MarkType.TEXT]: TextStrategy, [MarkType.SIGNATURE]: SignatureStrategy, - [MarkType.FULLNAME]: FullNameStrategy + [MarkType.FULLNAME]: FullNameStrategy, + [MarkType.JOBTITLE]: JobTitleStrategy, + [MarkType.DATETIME]: DateTimeStrategy } diff --git a/src/utils/mark.ts b/src/utils/mark.ts index 319371c..37bda6b 100644 --- a/src/utils/mark.ts +++ b/src/utils/mark.ts @@ -176,14 +176,12 @@ export const DEFAULT_TOOLBOX: DrawTool[] = [ { identifier: MarkType.JOBTITLE, icon: faBriefcase, - label: 'Job Title', - isComingSoon: true + label: 'Job Title' }, { identifier: MarkType.DATETIME, icon: faClock, - label: 'Date Time', - isComingSoon: true + label: 'Date Time' }, { identifier: MarkType.NUMBER, -- 2.43.0 From 8de86aac28c38fc4fb8d34eca04e0ce50b6ab13e Mon Sep 17 00:00:00 2001 From: en Date: Mon, 10 Mar 2025 09:44:09 +0000 Subject: [PATCH 05/10] fix(marks): date input --- src/components/MarkTypeStrategy/DateTime/Input.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/components/MarkTypeStrategy/DateTime/Input.tsx b/src/components/MarkTypeStrategy/DateTime/Input.tsx index fa68438..b2e864c 100644 --- a/src/components/MarkTypeStrategy/DateTime/Input.tsx +++ b/src/components/MarkTypeStrategy/DateTime/Input.tsx @@ -6,10 +6,9 @@ export const MarkInputDateTime = ({ handler, placeholder }: MarkInputProps) => { const ref = useRef(null) useEffect(() => { if (ref.current) { - ref.current.value = new Date().toISOString().slice(0, 16) - if (ref.current.valueAsDate) { - handler(ref.current.valueAsDate.toUTCString()) - } + const date = new Date() + ref.current.value = date.toISOString().slice(0, 16) + handler(date.toUTCString()) } }, [handler]) return ( -- 2.43.0 From 745ba377d4d10d3df1ecb4ae2731bf8229385c79 Mon Sep 17 00:00:00 2001 From: en Date: Mon, 10 Mar 2025 10:56:36 +0000 Subject: [PATCH 06/10] refactor(settings): remove cache links and page --- src/pages/settings/cache/index.tsx | 69 ------------------------------ src/routes/util.tsx | 9 ---- 2 files changed, 78 deletions(-) delete mode 100644 src/pages/settings/cache/index.tsx diff --git a/src/pages/settings/cache/index.tsx b/src/pages/settings/cache/index.tsx deleted file mode 100644 index 5dbf8af..0000000 --- a/src/pages/settings/cache/index.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import InputIcon from '@mui/icons-material/Input' -import IosShareIcon from '@mui/icons-material/IosShare' -import { - List, - ListItemButton, - ListItemIcon, - ListItemText, - ListSubheader, - useTheme -} from '@mui/material' -import { Container } from '../../../components/Container' -import { Footer } from '../../../components/Footer/Footer' - -export const CacheSettingsPage = () => { - const theme = useTheme() - - const listItem = (label: string) => { - return ( - - ) - } - - return ( - <> - - - Cache Setting - - } - > - - - - - {listItem('Export (coming soon)')} - - - - - - - {listItem('Import (coming soon)')} - - - -