Skip to content

Commit bd34872

Browse files
committed
[Page] Add a realistic example fof split save action use case
1 parent 2ae4d7c commit bd34872

File tree

2 files changed

+381
-1
lines changed

2 files changed

+381
-1
lines changed

polaris-react/src/components/Page/Page.stories.tsx

Lines changed: 183 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, {useState, useRef} from 'react';
22
import type {ComponentMeta} from '@storybook/react';
33
import {
44
DeleteMinor,
@@ -7,6 +7,7 @@ import {
77
ExternalMinor,
88
ViewMinor,
99
MobileVerticalDotsMajor,
10+
ChevronDownMinor,
1011
} from '@shopify/polaris-icons';
1112
import {
1213
Badge,
@@ -15,6 +16,13 @@ import {
1516
Page,
1617
PageActions,
1718
LegacyStack,
19+
Popover,
20+
ActionList,
21+
ButtonGroup,
22+
TextField,
23+
FormLayout,
24+
ContextualSaveBar,
25+
Frame,
1826
} from '@shopify/polaris';
1927

2028
export default {
@@ -346,3 +354,177 @@ export function WithContentAfterTitle() {
346354
</Page>
347355
);
348356
}
357+
358+
export function WithSplitSaveAction() {
359+
const initialState = {
360+
title: 'Jar With Lock-Lid',
361+
description: '',
362+
isDraft: false,
363+
};
364+
365+
const [active, setActive] = React.useState(false);
366+
const [title, setTitle] = useState('Jar With Lock-Lid');
367+
const [description, setDescription] = useState('');
368+
const [isDirty, setIsDirty] = useState(false);
369+
const [isDraft, setIsDraft] = useState(false);
370+
371+
const savedEditHistory = useRef<
372+
{
373+
title: string;
374+
description: string;
375+
isDraft: boolean;
376+
}[]
377+
>([]);
378+
379+
const handleChange = (name: string) => (value: string) => {
380+
switch (name) {
381+
case 'title':
382+
handleDirtyState(name, value, title);
383+
setTitle(value);
384+
break;
385+
case 'description':
386+
handleDirtyState(name, value, description);
387+
setDescription(value);
388+
break;
389+
default:
390+
null;
391+
}
392+
};
393+
394+
const handleDirtyState = (
395+
name: string,
396+
newValue: string,
397+
currentValue: string,
398+
) => {
399+
if (
400+
(newValue !== initialState[name] && !isDirty) ||
401+
newValue !== currentValue
402+
) {
403+
setIsDirty(true);
404+
} else {
405+
setIsDirty(false);
406+
}
407+
};
408+
409+
const handleDiscard = () => {
410+
const previousState: {
411+
title: string;
412+
description: string;
413+
isDraft: boolean;
414+
} = savedEditHistory.current.pop() ?? initialState;
415+
416+
setTitle(previousState.title);
417+
setDescription(previousState.description);
418+
setIsDraft(previousState.isDraft);
419+
setIsDirty(false);
420+
};
421+
422+
const splitButton = (
423+
<ButtonGroup segmented>
424+
<Button
425+
size="large"
426+
onClick={() => {
427+
savedEditHistory.current.push({title, description, isDraft: false});
428+
setIsDirty(false);
429+
setIsDraft(false);
430+
}}
431+
>
432+
Save
433+
</Button>
434+
435+
<Popover
436+
active={active}
437+
preferredAlignment="right"
438+
activator={
439+
<Button
440+
size="large"
441+
onClick={() => setActive(true)}
442+
icon={ChevronDownMinor}
443+
accessibilityLabel="Other save actions"
444+
/>
445+
}
446+
autofocusTarget="first-node"
447+
onClose={() => setActive(false)}
448+
zIndexOverride={514}
449+
>
450+
<ActionList
451+
actionRole="menuitem"
452+
items={[
453+
{
454+
content: 'Save as draft',
455+
onAction: () => {
456+
setIsDraft(true);
457+
savedEditHistory.current.push({
458+
title,
459+
description,
460+
isDraft: true,
461+
});
462+
},
463+
},
464+
]}
465+
onActionAnyItem={() => setIsDirty(false)}
466+
/>
467+
</Popover>
468+
</ButtonGroup>
469+
);
470+
471+
const saveBar = isDirty ? (
472+
<ContextualSaveBar
473+
message="Unsaved changes"
474+
saveAction={splitButton}
475+
discardAction={{
476+
content: 'Discard',
477+
onAction: handleDiscard,
478+
}}
479+
/>
480+
) : null;
481+
482+
console.log(savedEditHistory);
483+
484+
return (
485+
<Frame
486+
logo={{
487+
width: 124,
488+
contextualSaveBarSource:
489+
'https://cdn.shopify.com/s/files/1/0446/6937/files/jaded-pixel-logo-gray.svg?6215648040070010999',
490+
}}
491+
>
492+
{saveBar}
493+
<Page
494+
backAction={{content: 'Products', url: '#'}}
495+
title="Jar With Lock-Lid"
496+
titleMetadata={
497+
<Badge status={isDraft ? 'info' : 'success'}>
498+
{isDraft ? 'Draft' : 'Active'}
499+
</Badge>
500+
}
501+
secondaryActions={[
502+
{content: 'Duplicate'},
503+
{content: 'View on your store'},
504+
]}
505+
pagination={{
506+
hasPrevious: true,
507+
hasNext: true,
508+
}}
509+
>
510+
<LegacyCard sectioned>
511+
<FormLayout>
512+
<TextField
513+
autoComplete="off"
514+
label="Title"
515+
value={title}
516+
onChange={handleChange('title')}
517+
/>
518+
<TextField
519+
multiline
520+
autoComplete="off"
521+
label="Description"
522+
value={description}
523+
onChange={handleChange('description')}
524+
/>
525+
</FormLayout>
526+
</LegacyCard>
527+
</Page>
528+
</Frame>
529+
);
530+
}

0 commit comments

Comments
 (0)