PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / trunk
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance vtrunk
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / vendor / team-updraft / lib-onboarding-wizard / Wizard / Onboarding / src / components / Fields / Status.tsx

Status.tsx in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance trunk, at vendor/team-updraft/lib-onboarding-wizard/Wizard/Onboarding/src/components/Fields/Status.tsx

191 lines 6.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { memo } from '@wordpress/element';
2 import type { MouseEvent } from 'react';
3 import FieldWrapper from './FieldWrapper';
4 import ButtonInput from '../Inputs/ButtonInput';
5 import Icon from '../../utils/Icon';
6 import useOnboardingStore from '../../store/useOnboardingStore';
7 import useAlertStore from '../../store/useAlertStore';
8
9 interface StatusSection {
10 title: string;
11 content: string;
12 content_html?: string;
13 }
14
15 interface StatusAction {
16 type: 'button' | 'link';
17 label: string;
18 onClick?: string;
19 groupId?: string;
20 href?: string;
21 target?: string;
22 rel?: string;
23 }
24
25 interface StatusFieldConfig {
26 id: string;
27 label?: string;
28 context?: any;
29 context_html?: string;
30 container_class?: string;
31 title_class?: string;
32 content_class?: string;
33 actions_class?: string;
34 sections?: StatusSection[];
35 actions?: StatusAction[];
36 [key: string]: any;
37 }
38
39 interface StatusProps {
40 field: StatusFieldConfig;
41 value?: any;
42 onChange?: (value: any) => void;
43 }
44
45 const Status = ({ field }: StatusProps) => {
46 const { settings, setValue, getValue } = useOnboardingStore();
47 const { setAlertState, getAlertState } = useAlertStore();
48
49 const {
50 container_class = 'max-w-sm bg-gray-100 rounded-2xl p-6 text-gray-800',
51 title_class = 'text-lg font-semibold mb-1',
52 content_class = 'text-base mb-2',
53 actions_class = 'flex items-center gap-4 !text-[#C4511C] font-semibold',
54 sections = [],
55 actions = [],
56 } = field;
57
58 /**
59 * Resolve placeholders [[field_id]] using Zustand getValue.
60 */
61 const resolvePlaceholders = (text: string): string => {
62 if (!text || typeof text !== 'string') {
63 return text;
64 }
65 return text.replace(/\[\[([a-zA-Z0-9_\-]+)\]\]/g, (_match, fieldId) => String(getValue(fieldId)));
66 };
67
68 const renderSection = (section: StatusSection, index: number) => {
69 const resolvedContent = section.content_html
70 ? resolvePlaceholders(section.content_html)
71 : resolvePlaceholders(section.content);
72
73 return (
74 <div key={index}>
75 <h3 className={title_class}>
76 {section.title}
77 </h3>
78 {section.content_html ? (
79 <p
80 className={content_class}
81 dangerouslySetInnerHTML={{ __html: resolvedContent }}
82 />
83 ) : (
84 <p className={content_class}>
85 {resolvedContent}
86 </p>
87 )}
88 </div>
89 );
90 };
91
92 const renderAction = (action: StatusAction, index: number) => {
93 // Common button props
94 const buttonProps = {
95 key: index,
96 btnVariant: 'transparent' as const,
97 size: 'sm' as const,
98 rawClassName: 'flex items-center gap-1 hover:underline',
99 };
100
101 if (action.type === 'button') {
102 const handleClick = (e: MouseEvent<HTMLButtonElement>) => {
103 const actionName = action.onClick || '';
104 const groupId = action.groupId || field.id;
105 const actions = (window as any).pluginOnboardingActions || {};
106 const fn = actions[actionName];
107
108 if (typeof fn === 'function') {
109 try {
110 fn(field, settings, setAlertState, setValue);
111 } catch (e) {
112 console.error('Error in pluginOnboardingActions.' + actionName, e);
113 }
114 } else {
115 setValue(`${groupId}_completed`, false);
116 }
117 };
118
119 return (
120 <ButtonInput
121 {...buttonProps}
122 onClick={handleClick}
123 >
124 {action.label}
125 </ButtonInput>
126 );
127 }
128
129 if (action.type === 'link') {
130 return (
131 <ButtonInput
132 {...buttonProps}
133 link={action.href || '#'}
134 >
135 {action.label}
136 </ButtonInput>
137 );
138 }
139
140 return null;
141 };
142
143 const alertGroupId = field.alert_group_id || field.id;
144 const alertState = getAlertState(alertGroupId);
145 const isUpdating = alertState.isUpdating;
146
147 return (
148 <FieldWrapper
149 inputId={field.id}
150 label={field.label || ''}
151 context={field.context}
152 contextHtml={field.context_html ?? ''}
153 >
154 <div className="relative w-full">
155 <div
156 className={isUpdating ? 'pointer-events-none opacity-70' : ''}
157 aria-disabled={isUpdating}
158 >
159 <div className={container_class}>
160 {sections.map((section, index) => renderSection(section, index))}
161
162 {actions.length > 0 && (
163 <>
164 <h3 className={title_class}>
165 {field.actions_title || 'Manage'}
166 </h3>
167 <div className={actions_class}>
168 {actions.map((action, index) => renderAction(action, index))}
169 </div>
170 </>
171 )}
172 </div>
173 </div>
174
175 {isUpdating && (
176 <div className="absolute inset-0 flex items-center justify-center bg-white/60 cursor-not-allowed">
177 <Icon
178 name="loading-circle"
179 size={20}
180 color="var(--teamupdraft-orange-dark)"
181 fill="var(--teamupdraft-orange-dark)"
182 />
183 </div>
184 )}
185 </div>
186 </FieldWrapper>
187 );
188 };
189
190 export default memo(Status);
191