PluginProbe ʕ •ᴥ•ʔ
Presto Player / 4.3.2
Presto Player v4.3.2
4.3.2 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 2 months ago LabelWithTooltip.js 2 months ago ProGate.js 2 months ago SectionCard.js 2 months ago SettingsDataProvider.js 2 months ago SettingsPageShell.js 2 months ago UnsavedChangesDialog.js 2 months ago navigationGuard.js 2 months 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