diff --git a/sites/backend/src/models/pattern.mjs b/sites/backend/src/models/pattern.mjs index b52aebbaee2..c1a59aad22c 100644 --- a/sites/backend/src/models/pattern.mjs +++ b/sites/backend/src/models/pattern.mjs @@ -2,6 +2,7 @@ import { log } from '../utils/log.mjs' import { capitalize } from '../utils/index.mjs' import { setPatternAvatar } from '../utils/sanity.mjs' import yaml from 'js-yaml' +import { SetModel } from './set.mjs' export function PatternModel(tools) { this.config = tools.config @@ -11,6 +12,7 @@ export function PatternModel(tools) { this.rbac = tools.rbac this.encryptedFields = ['data', 'img', 'name', 'notes', 'settings'] this.clear = {} // For holding decrypted data + this.Set = new SetModel(tools) return this } @@ -218,8 +220,8 @@ PatternModel.prototype.reveal = async function () { } if (this.record.cset.measies) this.record.cset.measies = JSON.parse(this.record.cset.measies) } - if (this.record.set) { - if (this.record.set.measies) this.record.set.measies = JSON.parse(this.record.set.measies) + if (this.record?.set) { + this.record.set = this.Set.revealSet(this.record.set) } return this diff --git a/sites/org/pages/patterns/[id]/edit.mjs b/sites/org/pages/patterns/[id]/edit.mjs new file mode 100644 index 00000000000..27784f46253 --- /dev/null +++ b/sites/org/pages/patterns/[id]/edit.mjs @@ -0,0 +1,77 @@ +// Hooks +import { useEffect, useState } from 'react' +import { useAccount } from 'shared/hooks/use-account.mjs' +import { useBackend } from 'shared/hooks/use-backend.mjs' +import { useDesign } from 'shared/hooks/use-design.mjs' +// Dependencies +import { serverSideTranslations } from 'next-i18next/serverSideTranslations' +// Components +import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs' +import { Workbench, ns as wbNs } from 'shared/components/workbench/index.mjs' +import { WorkbenchLayout } from 'site/components/layouts/workbench.mjs' +import { Null } from 'shared/components/null.mjs' +import { DynamicOrgDocs as DynamicDocs } from 'site/components/dynamic-org-docs.mjs' + +// Translation namespaces used on this page +const namespaces = [...new Set(['aaron', ...wbNs, ...pageNs])] + +const EditPatternPage = ({ page, id }) => { + // State + const [pattern, setPattern] = useState(false) + + // Hooks + const { token } = useAccount() + const backend = useBackend(token) + const Design = useDesign(pattern?.design) + + // Effect + useEffect(() => { + const getPattern = async () => { + const result = await backend.getPattern(id) + if (result.success) setPattern(result.data.pattern) + } + // Guard against loops as the backend object is recreated on each render + if (pattern === false) getPattern() + else if (pattern.id && pattern.id !== id) getPattern() + }, [id, pattern.id, backend]) + + const baseSettings = pattern + ? { + ...pattern.settings, + measurements: pattern.set ? pattern.set.measies : pattern.cset.measies, + } + : null + + return ( + + + + ) +} + +export default EditPatternPage + +export async function getStaticProps({ locale, params }) { + return { + props: { + ...(await serverSideTranslations(locale, namespaces)), + id: Number(params.id), + page: { + locale, + path: ['new', 'pattern', 'aaron', 'set', params.id], + title: '', + }, + }, + } +} + +export async function getStaticPaths() { + return { + paths: [], + fallback: true, + } +} diff --git a/sites/shared/components/account/account.en.yaml b/sites/shared/components/account/account.en.yaml index b96ff74d343..6b6dce5f9b1 100644 --- a/sites/shared/components/account/account.en.yaml +++ b/sites/shared/components/account/account.en.yaml @@ -25,7 +25,7 @@ img: Profile image username: Username compare: Metricset Comparison consent: Consent & Privacy -control: Power versus Simplicity +control: User Experience imperial: Units units: Units apikeys: API Keys @@ -97,7 +97,7 @@ control4d: Reveals all features, keeps handrails and safety checks. control5t: Get out of my way control5d: Reveals all features, removes all handrails and safety checks. controlShowMore: Show more options -controlTitle: What do you prefer? +controlTitle: Which user experience do you prefer? # img imgTitle: How about a picture? imgDragAndDropImageHere: Drag and drop an image here diff --git a/sites/shared/components/account/control.mjs b/sites/shared/components/account/control.mjs index 13bcdbda03f..274aebf0e0a 100644 --- a/sites/shared/components/account/control.mjs +++ b/sites/shared/components/account/control.mjs @@ -13,7 +13,7 @@ import { ContinueButton } from 'shared/components/buttons/continue-button.mjs' export const ns = ['account', 'toast'] -export const ControlSettings = ({ title = false, welcome = false }) => { +export const ControlSettings = ({ title = false, welcome = false, noBack = false }) => { // Context const { startLoading, stopLoading } = useContext(LoadingContext) @@ -50,25 +50,16 @@ export const ControlSettings = ({ title = false, welcome = false }) => { return (
{title ?

{t('controlTitle')}

: null} - {[1, 2, 3, 4, 5].map((val) => { - if (selection === 1 && val > 2) return null - if (selection === 2 && val > 3) return null - if (selection === 3 && val > 4) return null - if (selection === 5 && val < 4) return null - else - return ( - - - {selection === 1 && val === 2 ? t('showMore') : t(`control${val}t`)} - - {selection > 1 ? ( - - {t(`control${val}d`)} - - ) : null} - - ) - })} + {[1, 2, 3, 4, 5].map((val) => ( + + {t(`control${val}t`)} + {selection > 1 ? ( + + {t(`control${val}d`)} + + ) : null} + + ))} {welcome ? ( <> @@ -86,7 +77,7 @@ export const ControlSettings = ({ title = false, welcome = false }) => { ) : null} - ) : ( + ) : noBack ? null : ( )}
diff --git a/sites/shared/components/account/patterns.mjs b/sites/shared/components/account/patterns.mjs index 2594e0e43b7..3c0df83c239 100644 --- a/sites/shared/components/account/patterns.mjs +++ b/sites/shared/components/account/patterns.mjs @@ -625,7 +625,6 @@ export const Patterns = ({ standAlone = false }) => { {t('createANewPattern')} {standAlone ? null : } -
{JSON.stringify(patterns, null, 2)}
) } diff --git a/sites/shared/components/account/shared.mjs b/sites/shared/components/account/shared.mjs index 4f79baff7c4..986e0a24f95 100644 --- a/sites/shared/components/account/shared.mjs +++ b/sites/shared/components/account/shared.mjs @@ -3,7 +3,7 @@ import Link from 'next/link' import { useTranslation } from 'next-i18next' import { CogIcon, - ControlIcon, + FingerprintIcon as ControlIcon, NewsletterIcon, UnitsIcon, CompareIcon, diff --git a/sites/shared/components/modal/spinner.mjs b/sites/shared/components/modal/spinner.mjs new file mode 100644 index 00000000000..c45d24a44f4 --- /dev/null +++ b/sites/shared/components/modal/spinner.mjs @@ -0,0 +1,8 @@ +import { ModalWrapper } from 'shared/components/wrappers/modal.mjs' +import { Spinner } from 'shared/components/spinner.mjs' + +export const ModalSpinner = ({ color = 'warning' }) => ( + + + +) diff --git a/sites/shared/components/workbench/header.mjs b/sites/shared/components/workbench/header.mjs index d5370844461..bbb6c3f641c 100644 --- a/sites/shared/components/workbench/header.mjs +++ b/sites/shared/components/workbench/header.mjs @@ -11,7 +11,7 @@ import { ClearIcon, CodeIcon, CutIcon, - HelpIcon, + FingerprintIcon, MenuIcon, OptionsIcon, PrintIcon, @@ -20,6 +20,8 @@ import { import { Ribbon } from 'shared/components/ribbon.mjs' import Link from 'next/link' import { ModalMenu } from 'site/components/navigation/modal-menu.mjs' +import { ModalWrapper } from 'shared/components/wrappers/modal.mjs' +import { ControlSettings } from 'shared/components/account/control.mjs' export const ns = ['workbench', 'sections'] @@ -150,8 +152,19 @@ const NavIcons = ({ setModal, setView, view }) => { - - + + setModal( + + +
+
+ ) + } + > +
) diff --git a/sites/shared/components/workbench/index.mjs b/sites/shared/components/workbench/index.mjs index 926394f02fa..ec3a5c603dc 100644 --- a/sites/shared/components/workbench/index.mjs +++ b/sites/shared/components/workbench/index.mjs @@ -10,17 +10,12 @@ import { objUpdate } from 'shared/utils.mjs' // Components import { WorkbenchHeader } from './header.mjs' import { ErrorView } from 'shared/components/error/view.mjs' +import { ModalSpinner } from 'shared/components/modal/spinner.mjs' // Views import { DraftView, ns as draftNs } from 'shared/components/workbench/views/draft/index.mjs' import { SaveView, ns as saveNs } from 'shared/components/workbench/views/save/index.mjs' -export const ns = ['workbench', ...draftNs, ...saveNs] - -const loadDefaultSettings = ({ locale = 'en', units = 'metric' }) => ({ - units, - locale, - embed: true, -}) +export const ns = ['account', 'workbench', ...draftNs, ...saveNs] const defaultUi = { renderer: 'react', @@ -28,31 +23,32 @@ const defaultUi = { const draftViews = ['draft', 'test'] -export const Workbench = ({ design, Design, set = false, DynamicDocs = false }) => { +export const Workbench = ({ design, Design, baseSettings, DynamicDocs, from }) => { // Hooks const { t, i18n } = useTranslation(ns) const { language } = i18n const { account } = useAccount() - const defaultSettings = loadDefaultSettings({ - units: account.imperial ? 'imperial' : 'metric', - locale: language, - }) - if (set) defaultSettings.measurements = set.measies - // State const [view, setView] = useView() - const [settings, setSettings] = useState({ ...defaultSettings, embed: true }) - const [ui, setUi] = useState({ ...defaultUi }) + const [settings, setSettings] = useState({ ...baseSettings, embed: true }) + const [ui, setUi] = useState(defaultUi) const [error, setError] = useState(false) - // Effects + // Effect useEffect(() => { - if (set.measies) update.settings('measurements', set.measies) - }, [set]) + // Force re-render when baseSettings changes. Required when they are loaded async. + setSettings({ ...baseSettings, embed: true }) + }, [baseSettings]) - // Don't bother without a set or Design - if (!set || !Design) return null + // Helper methods for settings/ui updates + const update = { + settings: (path, val) => setSettings(objUpdate({ ...settings }, path, val)), + ui: (path, val) => setUi(objUpdate({ ...ui }, path, val)), + } + + // Don't bother without a Design + if (!Design) return // Short-circuit errors early if (error) @@ -62,13 +58,7 @@ export const Workbench = ({ design, Design, set = false, DynamicDocs = false }) {error} ) - - // Helper methods for settings/ui updates - const update = { - settings: (path, val) => setSettings(objUpdate({ ...settings }, path, val)), - ui: (path, val) => setUi(objUpdate({ ...ui }, path, val)), - } - + console.log(baseSettings) // Deal with each view const viewProps = { account, @@ -108,7 +98,7 @@ export const Workbench = ({ design, Design, set = false, DynamicDocs = false }) } // Save view - else if (view === 'save') viewContent = + else if (view === 'save') viewContent = return ( <> diff --git a/sites/shared/components/workbench/menus/core-settings/index.mjs b/sites/shared/components/workbench/menus/core-settings/index.mjs index e0e10620272..65fc99e180e 100644 --- a/sites/shared/components/workbench/menus/core-settings/index.mjs +++ b/sites/shared/components/workbench/menus/core-settings/index.mjs @@ -146,7 +146,7 @@ export const Setting = ({ return ( } title={} buttons={buttons} @@ -167,26 +167,27 @@ export const CoreSettings = ({ language, account, DynamicDocs, + control, }) => { // FIXME: Update this namespace const { t } = useTranslation(['i18n', 'core-settings', design]) const { setModal } = useContext(ModalContext) + // For the simplest experience, not core settings are shown at all + if (control < 2) return null + const settingsConfig = loadSettingsConfig({ language, - control: account.control, + control, sabool: settings.sabool, parts: patternConfig.draftOrder, }) - // Default control level is 2 (in case people are not logged in) - const control = account.control || 2 const loadDocs = DynamicDocs ? (evt, setting = false) => { evt.stopPropagation() let path = `site/draft/core-settings` if (setting) path += `/${setting}` - console.log(path) setModal(
@@ -210,19 +211,20 @@ export const CoreSettings = ({ ) return ( - - {t('core-settings:coreSettings.t')} - -
- } - openTitle={t('core-settings:coreSettings')} - openButtons={openButtons} - > -

{t('core-settings:coreSettings.d')}

+ <> +
+ {control > 4 ? ( +
+ ) : ( + <> +
+ + {t('core-settings:coreSettings')} +
+

{t('core-settings:coreSettings.d')}

+ + )} +
{Object.keys(settingsConfig) .filter((name) => settingsConfig[name].control <= control) .map((name) => ( @@ -236,6 +238,6 @@ export const CoreSettings = ({ units={settings.units} /> ))} -
+ ) } diff --git a/sites/shared/components/workbench/menus/design-options/index.mjs b/sites/shared/components/workbench/menus/design-options/index.mjs index 6ead8300753..ec39c848507 100644 --- a/sites/shared/components/workbench/menus/design-options/index.mjs +++ b/sites/shared/components/workbench/menus/design-options/index.mjs @@ -173,8 +173,14 @@ export const DesignOptionGroup = ({ Option, t, loadDocs, + topLevel = false, }) => ( - } openTitle={t(group)}> + } + openTitle={t(group)} + > {Object.entries(options).map(([option, type]) => typeof type === 'string' ? (