PluginProbe ʕ •ᴥ•ʔ
Presto Player / trunk
Presto Player vtrunk
4.3.1 4.3.0 4.2.4 4.2.3 4.2.2 4.2.0 4.2.1 trunk 1.10.0 1.10.1 1.10.2 1.11.0 1.12.0 1.13.0 1.14.0 1.14.1 1.5.10 1.5.11 1.5.12 1.5.13 1.5.14 1.5.15 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.10 1.6.11 1.6.12 1.6.13 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.13 2.0.14 2.0.15 2.0.16 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.2.0 2.2.1 2.2.2 2.2.3 2.2.3-beta1 2.3.0 2.3.1 2.3.2 2.3.3 3.0.0 3.0.0-beta1 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.1.0 3.1.1 3.1.2 3.1.3 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4
presto-player / src / admin / dashboard / pages / settings / shared / SettingsPageShell.js
presto-player / src / admin / dashboard / pages / settings / shared Last commit date
ConfirmDialog.js 1 month ago LabelWithTooltip.js 1 month ago ProGate.js 1 month ago SectionCard.js 1 month ago SettingsDataProvider.js 1 month ago SettingsPageShell.js 1 month ago UnsavedChangesDialog.js 1 month ago navigationGuard.js 1 month ago
SettingsPageShell.js
93 lines
1 import { __ } from '@wordpress/i18n';
2 import { useEffect } from 'react';
3 import { Alert, Button, Container, Title } from '@bsf/force-ui';
4 import SettingsSectionSkeleton from '../../../components/Skeletons/SettingsSectionSkeleton';
5 import { useSettingsData } from './SettingsDataProvider';
6
7 const SettingsPageShell = ( {
8 title,
9 isDirty = false,
10 isSaving = false,
11 isLoading = false,
12 canSave,
13 onSave,
14 saveLabel,
15 children,
16 } ) => {
17 const { loadError, retryLoad } = useSettingsData();
18
19 // Browser-level guard: warns when closing tab / navigating away while dirty.
20 // Complements the in-app UnsavedChangesDialog (which only covers clicks
21 // inside the dashboard SPA).
22 useEffect( () => {
23 if ( ! isDirty ) {
24 return undefined;
25 }
26 const handler = ( event ) => {
27 event.preventDefault();
28 event.returnValue = '';
29 };
30 window.addEventListener( 'beforeunload', handler );
31 return () => window.removeEventListener( 'beforeunload', handler );
32 }, [ isDirty ] );
33
34 const label =
35 saveLabel ||
36 ( isSaving
37 ? __( 'Saving…', 'presto-player' )
38 : __( 'Save', 'presto-player' ) );
39
40 // canSave is an explicit override for pages with validation that should
41 // block *saving* without lying about isDirty (which still drives the
42 // unsaved-changes modal and beforeunload prompt). See BunnyNetPage's
43 // transcription-language invariant for a concrete use.
44 const saveEnabled = canSave !== undefined ? canSave : isDirty && ! isSaving;
45
46 // Pages that have nothing to persist (e.g. License) simply omit `onSave`
47 // — the shell skips the button entirely instead of showing a perpetually
48 // disabled control.
49 const showSave = typeof onSave === 'function';
50
51 return (
52 <div className="max-w-3xl w-full mx-auto flex flex-col gap-6">
53 <Container className="w-full flex items-center justify-between">
54 <Container.Item grow={ 1 }>
55 <Title title={ title } size="md" />
56 </Container.Item>
57 { showSave && (
58 <Container.Item>
59 <Button
60 size="sm"
61 disabled={ ! saveEnabled || isLoading || !! loadError }
62 onClick={ onSave }
63 >
64 { label }
65 </Button>
66 </Container.Item>
67 ) }
68 </Container>
69
70 { loadError && (
71 <Alert
72 design="stack"
73 variant="error"
74 title={ __( "Couldn't load settings", 'presto-player' ) }
75 content={ __(
76 'We hit an error fetching your settings. Save is disabled until the load succeeds — please retry.',
77 'presto-player'
78 ) }
79 action={ {
80 label: __( 'Retry', 'presto-player' ),
81 onClick: retryLoad,
82 type: 'button',
83 } }
84 />
85 ) }
86
87 { isLoading ? <SettingsSectionSkeleton /> : children }
88 </div>
89 );
90 };
91
92 export default SettingsPageShell;
93