From ed3585f9c8fac473a1acd7b46bf5b9e26fb8825d Mon Sep 17 00:00:00 2001 From: enes Date: Wed, 8 Jan 2025 13:59:35 +0100 Subject: [PATCH 1/9] fix(mod): reset form --- src/components/ModForm.tsx | 18 +++++------------- src/utils/mod.ts | 26 ++++++++++++++------------ 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/src/components/ModForm.tsx b/src/components/ModForm.tsx index 914db43..f539739 100644 --- a/src/components/ModForm.tsx +++ b/src/components/ModForm.tsx @@ -154,20 +154,12 @@ export const ModForm = () => { // Cancel if not confirmed if (!confirm) return - // Editing - if (mod) { - const initial = initializeFormState(mod) + // Reset fields to the initial or original existing data + const newState = initializeFormState(mod) - // Reset editor - editorRef.current?.setMarkdown(initial.body) - - // Reset fields to the original existing data - setFormState(initial) - return - } - - // New - set form state to the initial (clear form state) - setFormState(initializeFormState()) + // Reset editor + editorRef.current?.setMarkdown(newState.body) + setFormState(newState) } const handlePublish = () => { submit(JSON.stringify(formState), { diff --git a/src/utils/mod.ts b/src/utils/mod.ts index 71ceb39..3d40002 100644 --- a/src/utils/mod.ts +++ b/src/utils/mod.ts @@ -131,16 +131,18 @@ export const initializeFormState = ( originalAuthor: existingModData?.originalAuthor || undefined, screenshotsUrls: existingModData?.screenshotsUrls || [''], tags: existingModData?.tags.join(',') || '', - lTags: existingModData?.lTags || [], - LTags: existingModData?.LTags || [], - downloadUrls: existingModData?.downloadUrls || [ - { - url: '', - hash: '', - signatureKey: '', - malwareScanLink: '', - modVersion: '', - customNote: '' - } - ] + lTags: existingModData ? [...existingModData.lTags] : [], + LTags: existingModData ? [...existingModData.LTags] : [], + downloadUrls: existingModData + ? [...existingModData.downloadUrls.map((url) => ({ ...url }))] + : [ + { + url: '', + hash: '', + signatureKey: '', + malwareScanLink: '', + modVersion: '', + customNote: '' + } + ] }) From f214d667993cf886ebfb2d8156f65b47fe27375e Mon Sep 17 00:00:00 2001 From: enes Date: Thu, 9 Jan 2025 13:18:20 +0100 Subject: [PATCH 2/9] refactor(storage): util func moved --- src/hooks/useLocalStorage.tsx | 12 +----------- src/hooks/useSessionStorage.tsx | 12 +----------- src/utils/utils.ts | 11 +++++++++++ 3 files changed, 13 insertions(+), 22 deletions(-) diff --git a/src/hooks/useLocalStorage.tsx b/src/hooks/useLocalStorage.tsx index 10579cd..da1c641 100644 --- a/src/hooks/useLocalStorage.tsx +++ b/src/hooks/useLocalStorage.tsx @@ -1,6 +1,7 @@ import React, { useMemo } from 'react' import { getLocalStorageItem, + mergeWithInitialValue, removeLocalStorageItem, setLocalStorageItem } from 'utils' @@ -10,17 +11,6 @@ const useLocalStorageSubscribe = (callback: () => void) => { return () => window.removeEventListener('storage', callback) } -function mergeWithInitialValue(storedValue: T, initialValue: T): T { - if ( - !Array.isArray(storedValue) && - typeof storedValue === 'object' && - storedValue !== null - ) { - return { ...initialValue, ...storedValue } - } - return storedValue -} - export function useLocalStorage( key: string, initialValue: T diff --git a/src/hooks/useSessionStorage.tsx b/src/hooks/useSessionStorage.tsx index cc0756f..ca194e6 100644 --- a/src/hooks/useSessionStorage.tsx +++ b/src/hooks/useSessionStorage.tsx @@ -1,6 +1,7 @@ import React, { useMemo } from 'react' import { getSessionStorageItem, + mergeWithInitialValue, removeSessionStorageItem, setSessionStorageItem } from 'utils' @@ -10,17 +11,6 @@ const useSessionStorageSubscribe = (callback: () => void) => { return () => window.removeEventListener('sessionStorage', callback) } -function mergeWithInitialValue(storedValue: T, initialValue: T): T { - if ( - !Array.isArray(storedValue) && - typeof storedValue === 'object' && - storedValue !== null - ) { - return { ...initialValue, ...storedValue } - } - return storedValue -} - export function useSessionStorage( key: string, initialValue: T diff --git a/src/utils/utils.ts b/src/utils/utils.ts index e28027d..2f19e8e 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -180,3 +180,14 @@ export const getFallbackPubkey = () => { // Silently ignore } } + +export function mergeWithInitialValue(storedValue: T, initialValue: T): T { + if ( + !Array.isArray(storedValue) && + typeof storedValue === 'object' && + storedValue !== null + ) { + return { ...initialValue, ...storedValue } + } + return storedValue +} From b60659eebff856667a85c02e745dfba60ea0a5cf Mon Sep 17 00:00:00 2001 From: enes Date: Thu, 9 Jan 2025 13:19:17 +0100 Subject: [PATCH 3/9] feat(cache): add simple localcache hook --- src/hooks/index.ts | 1 + src/hooks/useLocalCache.tsx | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/hooks/useLocalCache.tsx diff --git a/src/hooks/index.ts b/src/hooks/index.ts index c01237e..e0f6038 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -9,3 +9,4 @@ export * from './useNDKContext' export * from './useScrollDisable' export * from './useLocalStorage' export * from './useSessionStorage' +export * from './useLocalCache' diff --git a/src/hooks/useLocalCache.tsx b/src/hooks/useLocalCache.tsx new file mode 100644 index 0000000..7dc1d9a --- /dev/null +++ b/src/hooks/useLocalCache.tsx @@ -0,0 +1,37 @@ +import { useCallback, useEffect, useState } from 'react' +import { setLocalStorageItem, removeLocalStorageItem } from 'utils' + +export function useLocalCache( + key: string +): [ + T | undefined, + React.Dispatch>, + () => void +] { + const [cache, setCache] = useState(() => { + const storedValue = window.localStorage.getItem(key) + if (storedValue === null) return undefined + + // Parse the value + const parsedStoredValue = JSON.parse(storedValue) + return parsedStoredValue + }) + + useEffect(() => { + try { + if (cache) { + setLocalStorageItem(key, JSON.stringify(cache)) + } else { + removeLocalStorageItem(key) + } + } catch (e) { + console.warn(e) + } + }, [cache, key]) + + const clearCache = useCallback(() => { + setCache(undefined) + }, []) + + return [cache, setCache, clearCache] +} From b3ade8e1d215688eebba07d98e2baac21d62e837 Mon Sep 17 00:00:00 2001 From: enes Date: Thu, 9 Jan 2025 13:20:11 +0100 Subject: [PATCH 4/9] style(categories): prettier formatting --- src/assets/categories/categories.json | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/assets/categories/categories.json b/src/assets/categories/categories.json index 15f8314..9166cb5 100644 --- a/src/assets/categories/categories.json +++ b/src/assets/categories/categories.json @@ -1,13 +1,19 @@ [ - { "name": "gameplay ", "sub": ["difficulty"]}, - { "name": "input", "sub": ["key mapping", "macro"]}, - { "name": "visual", "sub": ["textures", "lighting", "character models", "environment models"] }, + { "name": "gameplay ", "sub": ["difficulty"] }, + { "name": "input", "sub": ["key mapping", "macro"] }, + { + "name": "visual", + "sub": ["textures", "lighting", "character models", "environment models"] + }, { "name": "audio", "sub": ["sfx", "music", "voice"] }, { "name": "user interface", "sub": ["hud", "menu"] }, - { "name": "quality of life", "sub": ["bug fixes", "performance", "accessibility"] }, + { + "name": "quality of life", + "sub": ["bug fixes", "performance", "accessibility"] + }, "total conversions", "translation", "multiplayer", "clothing", - "Mod Manager" -] \ No newline at end of file + "mod manager" +] From 30a87cc34713bbcd497fbb2f488628208832cf76 Mon Sep 17 00:00:00 2001 From: enes Date: Thu, 9 Jan 2025 13:20:44 +0100 Subject: [PATCH 5/9] feat(cache): add mod cache --- src/components/ModForm.tsx | 69 +++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/src/components/ModForm.tsx b/src/components/ModForm.tsx index f539739..e17f646 100644 --- a/src/components/ModForm.tsx +++ b/src/components/ModForm.tsx @@ -31,6 +31,7 @@ import { Editor, EditorRef } from './Markdown/Editor' import { MEDIA_OPTIONS } from 'controllers' import { InputError } from './Inputs/Error' import { ImageUpload } from './Inputs/ImageUpload' +import { useLocalCache } from 'hooks/useLocalCache' interface GameOption { value: string @@ -45,9 +46,18 @@ export const ModForm = () => { const submit = useSubmit() const games = useGames() const [gameOptions, setGameOptions] = useState([]) + + // Enable cache for the new mod + const isEditing = typeof mod !== 'undefined' + const [cache, setCache, clearCache] = useLocalCache('draft-mod') const [formState, setFormState] = useState( - initializeFormState(mod) + isEditing ? initializeFormState(mod) : cache ? cache : initializeFormState() ) + + useEffect(() => { + !isEditing && setCache(formState) + }, [formState, isEditing, setCache]) + const editorRef = useRef(null) useEffect(() => { @@ -145,37 +155,42 @@ export const ModForm = () => { ) const [showConfirmPopup, setShowConfirmPopup] = useState(false) - const handleReset = () => { + const handleReset = useCallback(() => { setShowConfirmPopup(true) - } - const handleResetConfirm = (confirm: boolean) => { - setShowConfirmPopup(false) + }, []) + const handleResetConfirm = useCallback( + (confirm: boolean) => { + setShowConfirmPopup(false) - // Cancel if not confirmed - if (!confirm) return + // Cancel if not confirmed + if (!confirm) return - // Reset fields to the initial or original existing data - const newState = initializeFormState(mod) + // Reset fields to the initial or original existing data + const initialState = initializeFormState(mod) - // Reset editor - editorRef.current?.setMarkdown(newState.body) - setFormState(newState) - } - const handlePublish = () => { - submit(JSON.stringify(formState), { - method: mod ? 'put' : 'post', - encType: 'application/json' - }) - } + // Reset editor + editorRef.current?.setMarkdown(initialState.body) + setFormState(initialState) + + // Clear cache + !isEditing && clearCache() + }, + [clearCache, isEditing, mod] + ) + + const handlePublish = useCallback( + (e: React.FormEvent) => { + e.preventDefault() + submit(JSON.stringify(formState), { + method: isEditing ? 'put' : 'post', + encType: 'application/json' + }) + }, + [formState, isEditing, submit] + ) return ( -
{ - e.preventDefault() - handlePublish() - }} - > + { navigation.state === 'loading' || navigation.state === 'submitting' } > - {mod ? 'Reset' : 'Clear fields'} + {isEditing ? 'Reset' : 'Clear fields'}