@visns-studio/visns-components 6.2.0 → 6.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
92
92
|
},
|
|
93
93
|
"name": "@visns-studio/visns-components",
|
|
94
|
-
"version": "6.2.
|
|
94
|
+
"version": "6.2.1",
|
|
95
95
|
"description": "Various packages to assist in the development of our Custom Applications.",
|
|
96
96
|
"main": "src/index.js",
|
|
97
97
|
"files": [
|
|
@@ -40,7 +40,9 @@ import {
|
|
|
40
40
|
ChevronRight,
|
|
41
41
|
Copy,
|
|
42
42
|
List,
|
|
43
|
+
HelpCircle,
|
|
43
44
|
} from 'lucide-react';
|
|
45
|
+
import Swal from 'sweetalert2';
|
|
44
46
|
import { confirmDialog } from '../utils/ConfirmDialog';
|
|
45
47
|
|
|
46
48
|
import 'react-toggle/style.css';
|
|
@@ -1990,6 +1992,254 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
|
|
|
1990
1992
|
fetchRoles();
|
|
1991
1993
|
}, []);
|
|
1992
1994
|
|
|
1995
|
+
/* ---------------------------------------------------------------- */
|
|
1996
|
+
/* Guided help */
|
|
1997
|
+
/* ---------------------------------------------------------------- */
|
|
1998
|
+
|
|
1999
|
+
/**
|
|
2000
|
+
* Inline SVG for the guide's section headings. SweetAlert2 takes an HTML
|
|
2001
|
+
* string, so the lucide components used elsewhere in this file cannot be
|
|
2002
|
+
* rendered here — these mirror the same icons at the same weight.
|
|
2003
|
+
*/
|
|
2004
|
+
const helpIcon = (name, color) => {
|
|
2005
|
+
const open = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="${color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align: middle; display: inline-block;">`;
|
|
2006
|
+
const paths = {
|
|
2007
|
+
rocket: '<path d="M12 2c5 3 8 5 8 9a6 6 0 1 1-12 0c0-4 3-6 8-9Z"/><path d="m16 6-4 14-4-14"/><circle cx="12" cy="12" r="2"/>',
|
|
2008
|
+
list: '<line x1="8" x2="21" y1="6" y2="6"/><line x1="8" x2="21" y1="12" y2="12"/><line x1="8" x2="21" y1="18" y2="18"/><line x1="3" x2="3.01" y1="6" y2="6"/><line x1="3" x2="3.01" y1="12" y2="12"/><line x1="3" x2="3.01" y1="18" y2="18"/>',
|
|
2009
|
+
layers: '<path d="m12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83Z"/><path d="m22 12.5-9.17 4.16a2 2 0 0 1-1.66 0L2 12.5"/>',
|
|
2010
|
+
type: '<polyline points="4 7 4 4 20 4 20 7"/><line x1="9" x2="15" y1="20" y2="20"/><line x1="12" x2="12" y1="4" y2="20"/>',
|
|
2011
|
+
settings:
|
|
2012
|
+
'<path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/>',
|
|
2013
|
+
table: '<path d="M12 3v18"/><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M3 9h18"/><path d="M3 15h18"/>',
|
|
2014
|
+
branch: '<line x1="6" x2="6" y1="3" y2="15"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/>',
|
|
2015
|
+
flag: '<path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><line x1="4" x2="4" y1="22" y2="15"/>',
|
|
2016
|
+
save: '<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/>',
|
|
2017
|
+
help: '<circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><path d="M12 17h.01"/>',
|
|
2018
|
+
};
|
|
2019
|
+
return `${open}${paths[name] || paths.help}</svg>`;
|
|
2020
|
+
};
|
|
2021
|
+
|
|
2022
|
+
/** One heading style for every section of the guide. */
|
|
2023
|
+
const helpHeading = (icon, color, title) =>
|
|
2024
|
+
`<h3 style="color: #1f2937; margin: 0 0 12px 0; font-size: 16px; border-bottom: 2px solid ${color}; padding-bottom: 6px; display: flex; align-items: center; gap: 8px;">${helpIcon(
|
|
2025
|
+
icon,
|
|
2026
|
+
color
|
|
2027
|
+
)}${title}</h3>`;
|
|
2028
|
+
|
|
2029
|
+
/** A tinted panel with a bulleted body, optionally titled. */
|
|
2030
|
+
const helpPanel = ({ bg, border, text, title, items }) => `
|
|
2031
|
+
<div style="background: ${bg}; border: 1px solid ${border}; border-radius: 8px; padding: 12px; margin-bottom: 12px;">
|
|
2032
|
+
${
|
|
2033
|
+
title
|
|
2034
|
+
? `<h4 style="color: ${border}; margin: 0 0 8px 0; font-size: 14px;">${title}</h4>`
|
|
2035
|
+
: ''
|
|
2036
|
+
}
|
|
2037
|
+
<ul style="margin: 0; padding-left: 16px; color: ${text};">${items
|
|
2038
|
+
.map((item) => `<li>${item}</li>`)
|
|
2039
|
+
.join('')}</ul>
|
|
2040
|
+
</div>`;
|
|
2041
|
+
|
|
2042
|
+
/**
|
|
2043
|
+
* The end-user guide to building a template. Sections that describe an
|
|
2044
|
+
* opt-in feature are only included when this app actually switched that
|
|
2045
|
+
* feature on, so nobody is told about a control they will never see.
|
|
2046
|
+
*/
|
|
2047
|
+
const showGuidedHelp = () => {
|
|
2048
|
+
const sections = [
|
|
2049
|
+
helpHeading('rocket', '#3b82f6', 'What this screen is') +
|
|
2050
|
+
helpPanel({
|
|
2051
|
+
bg: '#f0f9ff',
|
|
2052
|
+
border: '#3b82f6',
|
|
2053
|
+
text: '#1e3a8a',
|
|
2054
|
+
items: [
|
|
2055
|
+
'This is the list of questions people will answer — for example a client review checklist',
|
|
2056
|
+
'<strong>Edit</strong> shows one compact row per question, with a summary of how it is set up',
|
|
2057
|
+
'<strong>Preview</strong> shows the form the way the person filling it in will see it',
|
|
2058
|
+
'<strong>Sections</strong> shows a strip of shortcuts, one per section; click one to jump to it',
|
|
2059
|
+
'Once there are more than five questions, a search box appears — matching questions stay bright and the rest dim',
|
|
2060
|
+
],
|
|
2061
|
+
}),
|
|
2062
|
+
|
|
2063
|
+
helpHeading('list', '#10b981', 'Adding and arranging questions') +
|
|
2064
|
+
helpPanel({
|
|
2065
|
+
bg: '#ecfdf5',
|
|
2066
|
+
border: '#10b981',
|
|
2067
|
+
text: '#065f46',
|
|
2068
|
+
items: dynamicFields
|
|
2069
|
+
? [
|
|
2070
|
+
'This template builds its own questions automatically, so there is no "Add Field" button',
|
|
2071
|
+
'Use the pencil to adjust a question, and the grip handle on the left to drag it into a new position',
|
|
2072
|
+
]
|
|
2073
|
+
: [
|
|
2074
|
+
'<strong>Add Field</strong> (bottom right) opens the question window',
|
|
2075
|
+
'The pencil edits a question, the copy icon duplicates it, the bin deletes it',
|
|
2076
|
+
'Duplicating a Section copies the section and every question inside it',
|
|
2077
|
+
'Drag the grip handle on the left to move a question; the up/down arrows let you type an exact position instead',
|
|
2078
|
+
'Deleting a question also clears any "show only when" rule that pointed at it, and tells you how many were cleared',
|
|
2079
|
+
],
|
|
2080
|
+
}),
|
|
2081
|
+
|
|
2082
|
+
helpHeading('layers', '#7c3aed', 'Sections and headings') +
|
|
2083
|
+
helpPanel({
|
|
2084
|
+
bg: '#f5f3ff',
|
|
2085
|
+
border: '#7c3aed',
|
|
2086
|
+
text: '#5b21b6',
|
|
2087
|
+
items: [
|
|
2088
|
+
'Add a question of type <strong>Section</strong> to start a new part of the form',
|
|
2089
|
+
'Everything after a Section belongs to it, until the next Section starts',
|
|
2090
|
+
'Questions before the first Section are listed under "Before first section"',
|
|
2091
|
+
'Click the arrow on a Section row to collapse or expand it while you work',
|
|
2092
|
+
'<strong>Heading</strong> is simpler — just a title on the page, with no grouping',
|
|
2093
|
+
'<strong>Plain Text</strong> is a block of formatted wording, for instructions or a declaration',
|
|
2094
|
+
],
|
|
2095
|
+
}),
|
|
2096
|
+
|
|
2097
|
+
helpHeading('type', '#0891b2', 'The kinds of question you can add') +
|
|
2098
|
+
helpPanel({
|
|
2099
|
+
bg: '#ecfeff',
|
|
2100
|
+
border: '#0891b2',
|
|
2101
|
+
text: '#155e75',
|
|
2102
|
+
items: [
|
|
2103
|
+
'<strong>Typed in:</strong> Text (one line), Textarea (several lines), Number',
|
|
2104
|
+
'<strong>Chosen from a list:</strong> Dropdown, Checkbox, Toggle (a yes/no switch)',
|
|
2105
|
+
'<strong>Dates and times:</strong> Date, Date & Time, Time',
|
|
2106
|
+
'<strong>Attached or drawn:</strong> File, Image, Video Upload, Signature, Canvas',
|
|
2107
|
+
'<strong>Grids:</strong> Table (Radio) and Table (Custom) — see below',
|
|
2108
|
+
'<strong>Layout only:</strong> Section, Heading, Plain Text',
|
|
2109
|
+
`<strong>Filled from your system:</strong> Dynamic Data pulls in a detail the system already holds${
|
|
2110
|
+
dynamicDropdowns && dynamicDropdowns.length > 0
|
|
2111
|
+
? ', and Dynamic Dropdown offers a list your system maintains'
|
|
2112
|
+
: ''
|
|
2113
|
+
}`,
|
|
2114
|
+
],
|
|
2115
|
+
}),
|
|
2116
|
+
|
|
2117
|
+
helpHeading('settings', '#f59e0b', 'Settings on each question') +
|
|
2118
|
+
helpPanel({
|
|
2119
|
+
bg: '#fffbeb',
|
|
2120
|
+
border: '#f59e0b',
|
|
2121
|
+
text: '#92400e',
|
|
2122
|
+
items: [
|
|
2123
|
+
'<strong>Label</strong> is the wording people read — write it as the question you want answered',
|
|
2124
|
+
'<strong>Required?</strong> set to Yes means the form cannot be submitted without an answer; required questions show an asterisk',
|
|
2125
|
+
'<strong>Size</strong> is how wide the question sits on the page: Full for its own row, Half or Quarter to share a row',
|
|
2126
|
+
'<strong>Height Size</strong> on a Textarea chooses a small, normal or large writing box',
|
|
2127
|
+
'<strong>Single or Bulk Image?</strong> decides whether one photo or several can be attached',
|
|
2128
|
+
'<strong>Associated Role?</strong> on a Signature says whose signature it is',
|
|
2129
|
+
'There is no help text, placeholder or preset answer — put any wording people need into the label, or a Plain Text block above',
|
|
2130
|
+
],
|
|
2131
|
+
}),
|
|
2132
|
+
|
|
2133
|
+
helpHeading('list', '#059669', 'Answers for Dropdown and Checkbox') +
|
|
2134
|
+
helpPanel({
|
|
2135
|
+
bg: '#f0fdf4',
|
|
2136
|
+
border: '#059669',
|
|
2137
|
+
text: '#166534',
|
|
2138
|
+
items: [
|
|
2139
|
+
'Type the answer in the box at the bottom of the Options list and press Enter, or click <strong>+ Add</strong>',
|
|
2140
|
+
'Click straight into an existing answer to reword it; the bin removes it',
|
|
2141
|
+
'Two answers cannot share the same wording',
|
|
2142
|
+
'Rewording an answer can unhook rules that were pointing at it — check any "show only when" rule that used it',
|
|
2143
|
+
],
|
|
2144
|
+
}),
|
|
2145
|
+
|
|
2146
|
+
helpHeading('table', '#be185d', 'Grid questions') +
|
|
2147
|
+
helpPanel({
|
|
2148
|
+
bg: '#fdf2f8',
|
|
2149
|
+
border: '#be185d',
|
|
2150
|
+
text: '#9d174d',
|
|
2151
|
+
items: [
|
|
2152
|
+
'<strong>Table (Radio)</strong> needs both Columns and Rows — the rows are the things being checked and the columns are the possible answers',
|
|
2153
|
+
'<strong>Table (Custom)</strong> needs Columns only, and gives one row of boxes to fill in',
|
|
2154
|
+
'Add a column or row by typing it in and pressing Enter, or clicking Add',
|
|
2155
|
+
'The rows are fixed when you build the template — the person filling in the form cannot add more',
|
|
2156
|
+
],
|
|
2157
|
+
}),
|
|
2158
|
+
|
|
2159
|
+
helpHeading(
|
|
2160
|
+
'branch',
|
|
2161
|
+
'#4f46e5',
|
|
2162
|
+
'Showing a question only when it applies'
|
|
2163
|
+
) +
|
|
2164
|
+
helpPanel({
|
|
2165
|
+
bg: '#eef2ff',
|
|
2166
|
+
border: '#4f46e5',
|
|
2167
|
+
text: '#3730a3',
|
|
2168
|
+
items: [
|
|
2169
|
+
'Every question window ends with <strong>Conditional Field Display Criteria</strong>',
|
|
2170
|
+
'Pick the earlier question it depends on, then either <strong>is</strong> with a value, or <strong>is filled in</strong>',
|
|
2171
|
+
'Only questions that come <em>before</em> this one can be used, and only ones that collect an answer',
|
|
2172
|
+
'A line at the bottom spells the rule out, e.g. "This field will only show when Advice type is Insurance"',
|
|
2173
|
+
'Leave it blank to always show the question, or use <strong>Clear rule</strong> to remove one',
|
|
2174
|
+
'Questions with a rule are marked "Conditional" in the list',
|
|
2175
|
+
],
|
|
2176
|
+
}),
|
|
2177
|
+
];
|
|
2178
|
+
|
|
2179
|
+
if (outstandingItems?.enabled) {
|
|
2180
|
+
sections.push(
|
|
2181
|
+
helpHeading('flag', '#d97706', 'Answers that raise a follow-up') +
|
|
2182
|
+
helpPanel({
|
|
2183
|
+
bg: '#fef3c7',
|
|
2184
|
+
border: '#d97706',
|
|
2185
|
+
text: '#92400e',
|
|
2186
|
+
items: [
|
|
2187
|
+
'On questions that offer answers, each answer has an <strong>Outstanding</strong> switch',
|
|
2188
|
+
'Turn it on for the answer that means "this needs following up", and the system raises an outstanding item when someone gives that answer',
|
|
2189
|
+
'Only one answer per question can be marked',
|
|
2190
|
+
'Leave every switch off to say this question never raises a follow-up',
|
|
2191
|
+
'If an amber warning appears, the answer the old rule pointed at no longer exists — set the switch again on the right answer',
|
|
2192
|
+
],
|
|
2193
|
+
})
|
|
2194
|
+
);
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
sections.push(
|
|
2198
|
+
helpHeading('save', '#dc2626', 'Saving your work') +
|
|
2199
|
+
helpPanel({
|
|
2200
|
+
bg: '#fef2f2',
|
|
2201
|
+
border: '#dc2626',
|
|
2202
|
+
text: '#991b1b',
|
|
2203
|
+
items: [
|
|
2204
|
+
'<strong>Save</strong> inside a question window only adds it to the list on screen — nothing is stored yet',
|
|
2205
|
+
'To store the template, click <strong>Edit Form</strong> (bottom right) and then <strong>Save</strong>',
|
|
2206
|
+
'Moving a question saves the whole template straight away, so the order is never lost',
|
|
2207
|
+
'If someone else changed this template while you had it open, you are told nothing was saved — reload the page before saving again, or your changes would undo theirs',
|
|
2208
|
+
],
|
|
2209
|
+
})
|
|
2210
|
+
);
|
|
2211
|
+
|
|
2212
|
+
Swal.fire({
|
|
2213
|
+
title: `<div style="display: flex; align-items: center; justify-content: center; gap: 8px;">${helpIcon(
|
|
2214
|
+
'help',
|
|
2215
|
+
'#3b82f6'
|
|
2216
|
+
)}Form Builder Guide</div>`,
|
|
2217
|
+
html: `<div style="text-align: left; font-size: 13px; line-height: 1.5; color: #374151; max-height: 70vh; overflow-y: auto;">${sections.join(
|
|
2218
|
+
'<div style="height: 12px;"></div>'
|
|
2219
|
+
)}</div>`,
|
|
2220
|
+
width: 800,
|
|
2221
|
+
confirmButtonText: 'Close',
|
|
2222
|
+
confirmButtonColor: '#6b7280',
|
|
2223
|
+
customClass: {
|
|
2224
|
+
popup: 'comprehensive-help-modal',
|
|
2225
|
+
htmlContainer: 'help-content-scrollable',
|
|
2226
|
+
},
|
|
2227
|
+
});
|
|
2228
|
+
};
|
|
2229
|
+
|
|
2230
|
+
// Show the guide once, the first time someone opens the builder.
|
|
2231
|
+
useEffect(() => {
|
|
2232
|
+
if (localStorage.getItem('formBuilder_hasSeenHelp')) return;
|
|
2233
|
+
|
|
2234
|
+
const timer = setTimeout(() => {
|
|
2235
|
+
showGuidedHelp();
|
|
2236
|
+
localStorage.setItem('formBuilder_hasSeenHelp', 'true');
|
|
2237
|
+
}, 500);
|
|
2238
|
+
|
|
2239
|
+
return () => clearTimeout(timer);
|
|
2240
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2241
|
+
}, []);
|
|
2242
|
+
|
|
1993
2243
|
return (
|
|
1994
2244
|
<div className={modalShow || modalFormShow ? styles.modalOpen : ''}>
|
|
1995
2245
|
<div className={styles.grid}>
|
|
@@ -2081,6 +2331,15 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
|
|
|
2081
2331
|
).length}{' '}
|
|
2082
2332
|
sections
|
|
2083
2333
|
</span>
|
|
2334
|
+
<button
|
|
2335
|
+
type="button"
|
|
2336
|
+
className={styles.toolBtn}
|
|
2337
|
+
onClick={showGuidedHelp}
|
|
2338
|
+
data-tooltip-id="action-tooltip"
|
|
2339
|
+
data-tooltip-content="How to build this form"
|
|
2340
|
+
>
|
|
2341
|
+
<HelpCircle size={15} /> Help
|
|
2342
|
+
</button>
|
|
2084
2343
|
<button
|
|
2085
2344
|
className={`${styles.toolBtn} ${
|
|
2086
2345
|
showOutline ? styles.toolBtnOn : ''
|
|
@@ -1752,224 +1752,56 @@ const GenericReportImproved = ({
|
|
|
1752
1752
|
return icons[iconName] || icons.chart;
|
|
1753
1753
|
};
|
|
1754
1754
|
|
|
1755
|
-
|
|
1756
|
-
|
|
1755
|
+
/* ---------------------------------------------------------------- */
|
|
1756
|
+
/* Guided help */
|
|
1757
|
+
/* ---------------------------------------------------------------- */
|
|
1758
|
+
|
|
1759
|
+
/**
|
|
1760
|
+
* One heading style for both guides, so the legacy and semantic help read
|
|
1761
|
+
* as the same help system. `icon` is a key of `getIcon`.
|
|
1762
|
+
*/
|
|
1763
|
+
const helpHeading = (icon, color, title) =>
|
|
1764
|
+
`<h3 style="color: #1f2937; margin: 0 0 12px 0; font-size: 16px; border-bottom: 2px solid ${color}; padding-bottom: 6px; display: flex; align-items: center; gap: 8px;">${getIcon(
|
|
1765
|
+
icon,
|
|
1766
|
+
color,
|
|
1767
|
+
16
|
|
1768
|
+
)}${title}</h3>`;
|
|
1769
|
+
|
|
1770
|
+
/**
|
|
1771
|
+
* A tinted panel with a bulleted body. Passing `items` as a string renders
|
|
1772
|
+
* it as a paragraph instead, for the short explanatory panels.
|
|
1773
|
+
*/
|
|
1774
|
+
const helpPanel = ({ bg, border, text, title, icon, items }) => {
|
|
1775
|
+
const body = Array.isArray(items)
|
|
1776
|
+
? `<ul style="margin: 0; padding-left: 16px; color: ${text};">${items
|
|
1777
|
+
.map((item) => `<li>${item}</li>`)
|
|
1778
|
+
.join('')}</ul>`
|
|
1779
|
+
: `<p style="margin: 0; color: ${text};">${items}</p>`;
|
|
1780
|
+
|
|
1781
|
+
return `
|
|
1782
|
+
<div style="background: ${bg}; border: 1px solid ${border}; border-radius: 8px; padding: 12px; margin-bottom: 12px;">
|
|
1783
|
+
${
|
|
1784
|
+
title
|
|
1785
|
+
? `<h4 style="color: ${border}; margin: 0 0 8px 0; font-size: 14px; display: flex; align-items: center; gap: 6px;">${
|
|
1786
|
+
icon ? getIcon(icon, border, 14) : ''
|
|
1787
|
+
}${title}</h4>`
|
|
1788
|
+
: ''
|
|
1789
|
+
}
|
|
1790
|
+
${body}
|
|
1791
|
+
</div>`;
|
|
1792
|
+
};
|
|
1793
|
+
|
|
1794
|
+
/** Shared SweetAlert2 options so both guides open the same way. */
|
|
1795
|
+
const showHelpModal = (titleIcon, titleText, sections) =>
|
|
1757
1796
|
Swal.fire({
|
|
1758
1797
|
title: `<div style="display: flex; align-items: center; justify-content: center; gap: 8px;">${getIcon(
|
|
1759
|
-
|
|
1798
|
+
titleIcon,
|
|
1760
1799
|
'#3b82f6',
|
|
1761
1800
|
24
|
|
1762
|
-
)}
|
|
1763
|
-
html:
|
|
1764
|
-
<div style="
|
|
1765
|
-
|
|
1766
|
-
<!-- Quick Start Section -->
|
|
1767
|
-
<div style="margin-bottom: 24px;">
|
|
1768
|
-
<h3 style="color: #1f2937; margin: 0 0 12px 0; font-size: 16px; border-bottom: 2px solid #3b82f6; padding-bottom: 6px; display: flex; align-items: center; gap: 8px;">
|
|
1769
|
-
${getIcon('rocket', '#3b82f6', 16)}
|
|
1770
|
-
Getting Started
|
|
1771
|
-
</h3>
|
|
1772
|
-
|
|
1773
|
-
<div style="background: #f0f9ff; border-left: 4px solid #3b82f6; padding: 12px; margin-bottom: 12px;">
|
|
1774
|
-
<h4 style="color: #1e40af; margin: 0 0 8px 0; font-size: 14px; display: flex; align-items: center; gap: 6px;">
|
|
1775
|
-
${getIcon('file', '#1e40af', 14)}
|
|
1776
|
-
Option 1: Use Saved Reports (Recommended)
|
|
1777
|
-
</h4>
|
|
1778
|
-
<p style="margin: 0 0 8px 0;">Click the "Templates" button to access pre-built reports for common needs like client lists, recent orders, or financial summaries.</p>
|
|
1779
|
-
<p style="margin: 0; font-style: italic; color: #1e40af;">Perfect for beginners and quick results!</p>
|
|
1780
|
-
</div>
|
|
1781
|
-
|
|
1782
|
-
<div style="background: #f9fafb; border-left: 4px solid #6b7280; padding: 12px;">
|
|
1783
|
-
<h4 style="color: #374151; margin: 0 0 8px 0; font-size: 14px; display: flex; align-items: center; gap: 6px;">
|
|
1784
|
-
${getIcon('cogs', '#374151', 14)}
|
|
1785
|
-
Option 2: Build Custom Report
|
|
1786
|
-
</h4>
|
|
1787
|
-
<p style="margin: 0;">Follow the 5-step wizard below to create exactly what you need.</p>
|
|
1788
|
-
</div>
|
|
1789
|
-
</div>
|
|
1790
|
-
|
|
1791
|
-
<!-- Step-by-Step Guide -->
|
|
1792
|
-
<div style="margin-bottom: 24px;">
|
|
1793
|
-
<h3 style="color: #1f2937; margin: 0 0 12px 0; font-size: 16px; border-bottom: 2px solid #10b981; padding-bottom: 6px; display: flex; align-items: center; gap: 8px;">
|
|
1794
|
-
${getIcon('list', '#10b981', 16)}
|
|
1795
|
-
5-Step Report Creation
|
|
1796
|
-
</h3>
|
|
1797
|
-
|
|
1798
|
-
<!-- Step 1 -->
|
|
1799
|
-
<div style="background: #ecfdf5; border: 1px solid #10b981; border-radius: 8px; padding: 12px; margin-bottom: 12px;">
|
|
1800
|
-
<h4 style="color: #047857; margin: 0 0 8px 0; font-size: 14px; display: flex; align-items: center; gap: 6px;">
|
|
1801
|
-
${getIcon('database', '#047857', 14)}
|
|
1802
|
-
Step 1: Choose Your Data Source
|
|
1803
|
-
</h4>
|
|
1804
|
-
<ul style="margin: 0; padding-left: 16px; color: #065f46;">
|
|
1805
|
-
<li>Select the main table (e.g., Clients, Orders, Invoices)</li>
|
|
1806
|
-
<li>This becomes the foundation of your report</li>
|
|
1807
|
-
<li>Look for the table icon to identify data types</li>
|
|
1808
|
-
</ul>
|
|
1809
|
-
</div>
|
|
1810
|
-
|
|
1811
|
-
<!-- Step 2 -->
|
|
1812
|
-
<div style="background: #eff6ff; border: 1px solid #3b82f6; border-radius: 8px; padding: 12px; margin-bottom: 12px;">
|
|
1813
|
-
<h4 style="color: #1e40af; margin: 0 0 8px 0; font-size: 14px; display: flex; align-items: center; gap: 6px;">
|
|
1814
|
-
${getIcon('columns', '#1e40af', 14)}
|
|
1815
|
-
Step 2: Select Columns
|
|
1816
|
-
</h4>
|
|
1817
|
-
<ul style="margin: 0; padding-left: 16px; color: #1e3a8a;">
|
|
1818
|
-
<li>Check the boxes for data you want to see</li>
|
|
1819
|
-
<li>Drag columns to reorder them</li>
|
|
1820
|
-
<li>Use "Select All" for comprehensive reports</li>
|
|
1821
|
-
<li>Preview shows how your data will look</li>
|
|
1822
|
-
</ul>
|
|
1823
|
-
</div>
|
|
1824
|
-
|
|
1825
|
-
<!-- Step 3 -->
|
|
1826
|
-
<div style="background: #fef3c7; border: 1px solid #f59e0b; border-radius: 8px; padding: 12px; margin-bottom: 12px;">
|
|
1827
|
-
<h4 style="color: #92400e; margin: 0 0 8px 0; font-size: 14px; display: flex; align-items: center; gap: 6px;">
|
|
1828
|
-
${getIcon('link', '#92400e', 14)}
|
|
1829
|
-
Step 3: Add Relationships (Optional)
|
|
1830
|
-
</h4>
|
|
1831
|
-
<ul style="margin: 0; padding-left: 16px; color: #92400e;">
|
|
1832
|
-
<li>Connect related data (e.g., add customer names to invoices)</li>
|
|
1833
|
-
<li>We suggest common relationships automatically</li>
|
|
1834
|
-
<li>Click "Add Relationship" to connect more tables</li>
|
|
1835
|
-
<li>This enriches your report with additional context</li>
|
|
1836
|
-
</ul>
|
|
1837
|
-
</div>
|
|
1838
|
-
|
|
1839
|
-
<!-- Step 4 -->
|
|
1840
|
-
<div style="background: #fdf2f8; border: 1px solid #ec4899; border-radius: 8px; padding: 12px; margin-bottom: 12px;">
|
|
1841
|
-
<h4 style="color: #be185d; margin: 0 0 8px 0; font-size: 14px; display: flex; align-items: center; gap: 6px;">
|
|
1842
|
-
${getIcon('filter', '#be185d', 14)}
|
|
1843
|
-
Step 4: Apply Filters (Optional)
|
|
1844
|
-
</h4>
|
|
1845
|
-
<ul style="margin: 0; padding-left: 16px; color: #be185d;">
|
|
1846
|
-
<li>Narrow down results (e.g., "Active clients only")</li>
|
|
1847
|
-
<li>Use AND/OR logic for complex conditions</li>
|
|
1848
|
-
<li>Group filters for advanced filtering</li>
|
|
1849
|
-
<li>Great for date ranges, status filters, etc.</li>
|
|
1850
|
-
</ul>
|
|
1851
|
-
</div>
|
|
1852
|
-
|
|
1853
|
-
<!-- Step 5 -->
|
|
1854
|
-
<div style="background: #f3e8ff; border: 1px solid #8b5cf6; border-radius: 8px; padding: 12px;">
|
|
1855
|
-
<h4 style="color: #7c3aed; margin: 0 0 8px 0; font-size: 14px; display: flex; align-items: center; gap: 6px;">
|
|
1856
|
-
${getIcon('download', '#7c3aed', 14)}
|
|
1857
|
-
Step 5: Generate & Export
|
|
1858
|
-
</h4>
|
|
1859
|
-
<ul style="margin: 0; padding-left: 16px; color: #7c3aed;">
|
|
1860
|
-
<li>Click "Generate Report" to see your data</li>
|
|
1861
|
-
<li>Review and refine as needed</li>
|
|
1862
|
-
<li>Export as Excel, CSV, or PDF</li>
|
|
1863
|
-
<li>Save the report template for future use</li>
|
|
1864
|
-
</ul>
|
|
1865
|
-
</div>
|
|
1866
|
-
</div>
|
|
1867
|
-
|
|
1868
|
-
<!-- Pro Tips Section -->
|
|
1869
|
-
<div style="margin-bottom: 20px;">
|
|
1870
|
-
<h3 style="color: #1f2937; margin: 0 0 12px 0; font-size: 16px; border-bottom: 2px solid #f59e0b; padding-bottom: 6px; display: flex; align-items: center; gap: 8px;">
|
|
1871
|
-
${getIcon('star', '#f59e0b', 16)}
|
|
1872
|
-
Pro Tips
|
|
1873
|
-
</h3>
|
|
1874
|
-
|
|
1875
|
-
<div style="background: #fffbeb; border: 1px solid #f59e0b; border-radius: 8px; padding: 12px;">
|
|
1876
|
-
<ul style="margin: 0; padding-left: 16px; color: #92400e;">
|
|
1877
|
-
<li><strong>Start Simple:</strong> Begin with basic reports, then add complexity</li>
|
|
1878
|
-
<li><strong>Use Previews:</strong> Check the preview before generating large reports</li>
|
|
1879
|
-
<li><strong>Save Templates:</strong> Save frequently used reports as templates</li>
|
|
1880
|
-
<li><strong>Date Filters:</strong> Use date ranges for better performance</li>
|
|
1881
|
-
<li><strong>Column Limits:</strong> Too many columns can slow down reports</li>
|
|
1882
|
-
</ul>
|
|
1883
|
-
</div>
|
|
1884
|
-
</div>
|
|
1885
|
-
|
|
1886
|
-
<!-- Common Use Cases -->
|
|
1887
|
-
<div style="margin-bottom: 20px;">
|
|
1888
|
-
<h3 style="color: #1f2937; margin: 0 0 12px 0; font-size: 16px; border-bottom: 2px solid #10b981; padding-bottom: 6px; display: flex; align-items: center; gap: 8px;">
|
|
1889
|
-
${getIcon('lightbulb', '#10b981', 16)}
|
|
1890
|
-
Common Report Examples
|
|
1891
|
-
</h3>
|
|
1892
|
-
|
|
1893
|
-
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 8px;">
|
|
1894
|
-
<div style="background: #f0fdf4; border: 1px solid #22c55e; border-radius: 6px; padding: 8px;">
|
|
1895
|
-
<strong style="color: #15803d;">${getIcon(
|
|
1896
|
-
'users',
|
|
1897
|
-
'#15803d',
|
|
1898
|
-
12
|
|
1899
|
-
)}Client List:</strong>
|
|
1900
|
-
<br><small style="color: #16a34a;">Clients table + Contact details</small>
|
|
1901
|
-
</div>
|
|
1902
|
-
<div style="background: #eff6ff; border: 1px solid #3b82f6; border-radius: 6px; padding: 8px;">
|
|
1903
|
-
<strong style="color: #1d4ed8;">${getIcon(
|
|
1904
|
-
'cart',
|
|
1905
|
-
'#1d4ed8',
|
|
1906
|
-
12
|
|
1907
|
-
)}Recent Orders:</strong>
|
|
1908
|
-
<br><small style="color: #2563eb;">Orders + Customer names + Date filter</small>
|
|
1909
|
-
</div>
|
|
1910
|
-
<div style="background: #fef3c7; border: 1px solid #f59e0b; border-radius: 6px; padding: 8px;">
|
|
1911
|
-
<strong style="color: #d97706;">${getIcon(
|
|
1912
|
-
'money',
|
|
1913
|
-
'#d97706',
|
|
1914
|
-
12
|
|
1915
|
-
)}Financial Summary:</strong>
|
|
1916
|
-
<br><small style="color: #f59e0b;">Invoices + Payments + Date grouping</small>
|
|
1917
|
-
</div>
|
|
1918
|
-
<div style="background: #fdf2f8; border: 1px solid #ec4899; border-radius: 6px; padding: 8px;">
|
|
1919
|
-
<strong style="color: #db2777;">${getIcon(
|
|
1920
|
-
'tasks',
|
|
1921
|
-
'#db2777',
|
|
1922
|
-
12
|
|
1923
|
-
)}Active Projects:</strong>
|
|
1924
|
-
<br><small style="color: #ec4899;">Projects + Status filter + Team members</small>
|
|
1925
|
-
</div>
|
|
1926
|
-
</div>
|
|
1927
|
-
</div>
|
|
1928
|
-
|
|
1929
|
-
<!-- Troubleshooting -->
|
|
1930
|
-
<div>
|
|
1931
|
-
<h3 style="color: #1f2937; margin: 0 0 12px 0; font-size: 16px; border-bottom: 2px solid #dc2626; padding-bottom: 6px; display: flex; align-items: center; gap: 8px;">
|
|
1932
|
-
${getIcon('settings', '#dc2626', 16)}
|
|
1933
|
-
Common Issues
|
|
1934
|
-
</h3>
|
|
1935
|
-
|
|
1936
|
-
<div style="background: #fef2f2; border: 1px solid #dc2626; border-radius: 8px; padding: 12px;">
|
|
1937
|
-
<div style="margin-bottom: 8px;">
|
|
1938
|
-
<strong style="color: #dc2626;">${getIcon(
|
|
1939
|
-
'clock',
|
|
1940
|
-
'#dc2626',
|
|
1941
|
-
12
|
|
1942
|
-
)}Report too slow?</strong>
|
|
1943
|
-
<span style="color: #991b1b;"> Add date filters or reduce columns</span>
|
|
1944
|
-
</div>
|
|
1945
|
-
<div style="margin-bottom: 8px;">
|
|
1946
|
-
<strong style="color: #dc2626;">${getIcon(
|
|
1947
|
-
'question',
|
|
1948
|
-
'#dc2626',
|
|
1949
|
-
12
|
|
1950
|
-
)}Missing data?</strong>
|
|
1951
|
-
<span style="color: #991b1b;"> Check relationships and join conditions</span>
|
|
1952
|
-
</div>
|
|
1953
|
-
<div style="margin-bottom: 8px;">
|
|
1954
|
-
<strong style="color: #dc2626;">${getIcon(
|
|
1955
|
-
'warning',
|
|
1956
|
-
'#dc2626',
|
|
1957
|
-
12
|
|
1958
|
-
)}Export failing?</strong>
|
|
1959
|
-
<span style="color: #991b1b;"> Try smaller date ranges or fewer rows</span>
|
|
1960
|
-
</div>
|
|
1961
|
-
<div>
|
|
1962
|
-
<strong style="color: #dc2626;">${getIcon(
|
|
1963
|
-
'eye',
|
|
1964
|
-
'#dc2626',
|
|
1965
|
-
12
|
|
1966
|
-
)}No data showing?</strong>
|
|
1967
|
-
<span style="color: #991b1b;"> Review your filter conditions</span>
|
|
1968
|
-
</div>
|
|
1969
|
-
</div>
|
|
1970
|
-
</div>
|
|
1971
|
-
</div>
|
|
1972
|
-
`,
|
|
1801
|
+
)}${titleText}</div>`,
|
|
1802
|
+
html: `<div style="text-align: left; font-size: 13px; line-height: 1.5; color: #374151; max-height: 70vh; overflow-y: auto;">${sections.join(
|
|
1803
|
+
'<div style="height: 12px;"></div>'
|
|
1804
|
+
)}</div>`,
|
|
1973
1805
|
width: 800,
|
|
1974
1806
|
confirmButtonText: 'Close',
|
|
1975
1807
|
confirmButtonColor: '#6b7280',
|
|
@@ -1980,7 +1812,324 @@ const GenericReportImproved = ({
|
|
|
1980
1812
|
htmlContainer: 'help-content-scrollable',
|
|
1981
1813
|
},
|
|
1982
1814
|
});
|
|
1983
|
-
|
|
1815
|
+
|
|
1816
|
+
/**
|
|
1817
|
+
* Help for the semantic wizard: the user picks subjects, related areas and
|
|
1818
|
+
* details by their business names, so the guide never mentions a table, a
|
|
1819
|
+
* column or a join.
|
|
1820
|
+
*/
|
|
1821
|
+
const showSemanticGuidedHelp = () =>
|
|
1822
|
+
showHelpModal('chart', 'Report Builder Guide', [
|
|
1823
|
+
helpHeading('rocket', '#3b82f6', 'Getting started') +
|
|
1824
|
+
helpPanel({
|
|
1825
|
+
bg: '#f0f9ff',
|
|
1826
|
+
border: '#3b82f6',
|
|
1827
|
+
text: '#1e3a8a',
|
|
1828
|
+
icon: 'file',
|
|
1829
|
+
title: 'Open a report someone already built',
|
|
1830
|
+
items: [
|
|
1831
|
+
'The builder opens on "Choose a Starting Point"',
|
|
1832
|
+
'Click any saved report to open it, change it and run it',
|
|
1833
|
+
'A padlock means only you can see it; a globe means everyone can',
|
|
1834
|
+
],
|
|
1835
|
+
}) +
|
|
1836
|
+
helpPanel({
|
|
1837
|
+
bg: '#f9fafb',
|
|
1838
|
+
border: '#6b7280',
|
|
1839
|
+
text: '#374151',
|
|
1840
|
+
icon: 'cogs',
|
|
1841
|
+
title: 'Build a new one',
|
|
1842
|
+
items: [
|
|
1843
|
+
'Click "Create New Report" and work through the six steps',
|
|
1844
|
+
'Only two things are compulsory: what the report is about, and at least one detail to show',
|
|
1845
|
+
'Related information, filters and grouping can all be skipped',
|
|
1846
|
+
],
|
|
1847
|
+
}),
|
|
1848
|
+
|
|
1849
|
+
helpHeading('list', '#10b981', 'The six steps') +
|
|
1850
|
+
helpPanel({
|
|
1851
|
+
bg: '#ecfdf5',
|
|
1852
|
+
border: '#10b981',
|
|
1853
|
+
text: '#065f46',
|
|
1854
|
+
icon: 'database',
|
|
1855
|
+
title: '1. Choose Your Subject',
|
|
1856
|
+
items: [
|
|
1857
|
+
'Each card is a kind of record your practice keeps, in plain English',
|
|
1858
|
+
'The card tells you how many details and related areas it has',
|
|
1859
|
+
'Pick the one you want one row per — for example one row per client',
|
|
1860
|
+
],
|
|
1861
|
+
}) +
|
|
1862
|
+
helpPanel({
|
|
1863
|
+
bg: '#eff6ff',
|
|
1864
|
+
border: '#3b82f6',
|
|
1865
|
+
text: '#1e3a8a',
|
|
1866
|
+
icon: 'link',
|
|
1867
|
+
title: '2. Add Related Data (optional)',
|
|
1868
|
+
items: [
|
|
1869
|
+
'Each card is an area already connected to your subject — nothing to set up',
|
|
1870
|
+
'Click one to make its details available at the next step',
|
|
1871
|
+
'Once added, areas connected to that one appear too, up to three steps out',
|
|
1872
|
+
'An area marked "many per record" can repeat a record across several rows',
|
|
1873
|
+
],
|
|
1874
|
+
}) +
|
|
1875
|
+
helpPanel({
|
|
1876
|
+
bg: '#f0fdf4',
|
|
1877
|
+
border: '#22c55e',
|
|
1878
|
+
text: '#166534',
|
|
1879
|
+
icon: 'columns',
|
|
1880
|
+
title: '3. Choose Information',
|
|
1881
|
+
items: [
|
|
1882
|
+
'Details are listed under the area they come from, then sorted into Details, Amounts & numbers, Dates, and Status & yes/no',
|
|
1883
|
+
'Tick anything you want as a column',
|
|
1884
|
+
'Each ticked detail gets a "Show as" picker — see Totals and counts below',
|
|
1885
|
+
'"Columns in your report" lists your choices left to right; use Up, Down and the X to reorder or remove them',
|
|
1886
|
+
],
|
|
1887
|
+
}) +
|
|
1888
|
+
helpPanel({
|
|
1889
|
+
bg: '#fdf2f8',
|
|
1890
|
+
border: '#ec4899',
|
|
1891
|
+
text: '#9d174d',
|
|
1892
|
+
icon: 'filter',
|
|
1893
|
+
title: '4. Filter Results (optional)',
|
|
1894
|
+
items: [
|
|
1895
|
+
'Add a condition, choose a detail, then a plain-English test: is, is not, contains, is between, is more than, is blank, is any of, and so on',
|
|
1896
|
+
'The value box matches the detail — a date picker for dates, a list of choices for a status',
|
|
1897
|
+
'Switch a group between "all of these" and "any of these"',
|
|
1898
|
+
'Add a nested group to mix the two, e.g. active AND (has email OR has phone)',
|
|
1899
|
+
'No conditions means every record is included',
|
|
1900
|
+
],
|
|
1901
|
+
}) +
|
|
1902
|
+
helpPanel({
|
|
1903
|
+
bg: '#fef3c7',
|
|
1904
|
+
border: '#f59e0b',
|
|
1905
|
+
text: '#92400e',
|
|
1906
|
+
icon: 'database',
|
|
1907
|
+
title: '5. Group & Order (optional)',
|
|
1908
|
+
items: [
|
|
1909
|
+
'Tick a column to break the results into sections by its value',
|
|
1910
|
+
'Only plain columns can be grouped — a summarised column is the answer, not the heading',
|
|
1911
|
+
'Add one or more sorts to control the row order, each A to Z / low to high or the reverse',
|
|
1912
|
+
],
|
|
1913
|
+
}) +
|
|
1914
|
+
helpPanel({
|
|
1915
|
+
bg: '#f3e8ff',
|
|
1916
|
+
border: '#8b5cf6',
|
|
1917
|
+
text: '#6b21a8',
|
|
1918
|
+
icon: 'eye',
|
|
1919
|
+
title: '6. Preview & Save',
|
|
1920
|
+
items: [
|
|
1921
|
+
'Answer any run-time questions, then click "Run report"',
|
|
1922
|
+
'Results appear 10, 25, 50 or 100 rows at a time',
|
|
1923
|
+
'Save the report, and export the results when they look right',
|
|
1924
|
+
],
|
|
1925
|
+
}),
|
|
1926
|
+
|
|
1927
|
+
helpHeading('money', '#0891b2', 'Totals, counts and averages') +
|
|
1928
|
+
helpPanel({
|
|
1929
|
+
bg: '#ecfeff',
|
|
1930
|
+
border: '#0891b2',
|
|
1931
|
+
text: '#155e75',
|
|
1932
|
+
items: [
|
|
1933
|
+
'"Show as" is set to <strong>Value</strong> by default, which simply lists the detail',
|
|
1934
|
+
'Change it to <strong>Total</strong>, <strong>Average</strong>, <strong>Lowest</strong> or <strong>Highest</strong> on amounts and numbers, <strong>Earliest</strong> or <strong>Latest</strong> on dates, and <strong>Count</strong> on anything',
|
|
1935
|
+
'As soon as one column is summarised, the report collapses to one row per combination of the plain columns you kept',
|
|
1936
|
+
'So for totals by adviser: choose Clients, show the adviser’s name as Value and the fee amount as Total — you get one row per adviser',
|
|
1937
|
+
'If you also tick grouping at step 5 while a column is summarised, tick <em>every</em> plain column, or the report will be refused',
|
|
1938
|
+
],
|
|
1939
|
+
}),
|
|
1940
|
+
|
|
1941
|
+
helpHeading('question', '#7c3aed', 'Reports that ask a question each time') +
|
|
1942
|
+
helpPanel({
|
|
1943
|
+
bg: '#f5f3ff',
|
|
1944
|
+
border: '#7c3aed',
|
|
1945
|
+
text: '#5b21b6',
|
|
1946
|
+
items: [
|
|
1947
|
+
'On any condition, tick "Ask me for this each time I run it"',
|
|
1948
|
+
'The value is left out of the saved report and asked for instead, under "Before we run this report"',
|
|
1949
|
+
'Give each question a clear name — that wording is what everyone else will see',
|
|
1950
|
+
'Untick "Must be answered" to make a question optional',
|
|
1951
|
+
'Ideal for anything that changes week to week, such as a date range',
|
|
1952
|
+
],
|
|
1953
|
+
}),
|
|
1954
|
+
|
|
1955
|
+
helpHeading('users', '#059669', 'Saving and sharing') +
|
|
1956
|
+
helpPanel({
|
|
1957
|
+
bg: '#ecfdf5',
|
|
1958
|
+
border: '#059669',
|
|
1959
|
+
text: '#065f46',
|
|
1960
|
+
items: [
|
|
1961
|
+
'"Save report" asks for a name and whether to make it public',
|
|
1962
|
+
'Private reports (padlock) are yours; public ones (globe) are visible to other users',
|
|
1963
|
+
'Opening a saved report and saving again updates it — use the copy option to keep the original',
|
|
1964
|
+
'A saved report stores the recipe, not the results, so it always runs against today’s data',
|
|
1965
|
+
],
|
|
1966
|
+
}),
|
|
1967
|
+
|
|
1968
|
+
helpHeading('download', '#b45309', 'Exporting') +
|
|
1969
|
+
helpPanel({
|
|
1970
|
+
bg: '#fffbeb',
|
|
1971
|
+
border: '#b45309',
|
|
1972
|
+
text: '#92400e',
|
|
1973
|
+
items: [
|
|
1974
|
+
'Run the report first, then choose Excel, CSV or PDF from "Export as"',
|
|
1975
|
+
'The export covers the whole report, not just the page on screen',
|
|
1976
|
+
'PDF suits short reports; use Excel or CSV for long ones',
|
|
1977
|
+
],
|
|
1978
|
+
}),
|
|
1979
|
+
|
|
1980
|
+
helpHeading('warning', '#dc2626', 'Good to know') +
|
|
1981
|
+
helpPanel({
|
|
1982
|
+
bg: '#fef2f2',
|
|
1983
|
+
border: '#dc2626',
|
|
1984
|
+
text: '#991b1b',
|
|
1985
|
+
items: [
|
|
1986
|
+
'Deleted records are left out of reports entirely — they are missing from the rows, and from every count and total',
|
|
1987
|
+
'Adding a "many per record" area can multiply your rows; summarise it instead to keep one row per record',
|
|
1988
|
+
'Nothing shown at all? Check your conditions at step 4 — one condition too many is the usual cause',
|
|
1989
|
+
'If the report is refused, the message on screen names the detail that caused it',
|
|
1990
|
+
],
|
|
1991
|
+
}),
|
|
1992
|
+
]);
|
|
1993
|
+
|
|
1994
|
+
/**
|
|
1995
|
+
* Help for the legacy table/column wizard, used when the newer report
|
|
1996
|
+
* engine is not available.
|
|
1997
|
+
*/
|
|
1998
|
+
const showLegacyGuidedHelp = () =>
|
|
1999
|
+
showHelpModal('chart', 'Complete Report Builder Guide', [
|
|
2000
|
+
helpHeading('rocket', '#3b82f6', 'Getting Started') +
|
|
2001
|
+
helpPanel({
|
|
2002
|
+
bg: '#f0f9ff',
|
|
2003
|
+
border: '#3b82f6',
|
|
2004
|
+
text: '#1e3a8a',
|
|
2005
|
+
icon: 'file',
|
|
2006
|
+
title: 'Option 1: Start from a saved report (recommended)',
|
|
2007
|
+
items: [
|
|
2008
|
+
'The builder opens on "Choose a Starting Point"',
|
|
2009
|
+
'Click any saved report to open it and adjust it',
|
|
2010
|
+
'A padlock means only you can see it; a globe means everyone can',
|
|
2011
|
+
],
|
|
2012
|
+
}) +
|
|
2013
|
+
helpPanel({
|
|
2014
|
+
bg: '#f9fafb',
|
|
2015
|
+
border: '#6b7280',
|
|
2016
|
+
text: '#374151',
|
|
2017
|
+
icon: 'cogs',
|
|
2018
|
+
title: 'Option 2: Build a custom report',
|
|
2019
|
+
items: [
|
|
2020
|
+
'Click "Create New Report" and follow the six steps below',
|
|
2021
|
+
],
|
|
2022
|
+
}),
|
|
2023
|
+
|
|
2024
|
+
helpHeading('list', '#10b981', 'Six steps to a report') +
|
|
2025
|
+
helpPanel({
|
|
2026
|
+
bg: '#ecfdf5',
|
|
2027
|
+
border: '#10b981',
|
|
2028
|
+
text: '#065f46',
|
|
2029
|
+
icon: 'database',
|
|
2030
|
+
title: 'Step 1: Select Your Data',
|
|
2031
|
+
items: [
|
|
2032
|
+
'Choose the main data source your report is about',
|
|
2033
|
+
'This becomes the foundation of the report',
|
|
2034
|
+
'You can bring in related data at the next step',
|
|
2035
|
+
],
|
|
2036
|
+
}) +
|
|
2037
|
+
helpPanel({
|
|
2038
|
+
bg: '#fef3c7',
|
|
2039
|
+
border: '#f59e0b',
|
|
2040
|
+
text: '#92400e',
|
|
2041
|
+
icon: 'link',
|
|
2042
|
+
title: 'Step 2: Add Related Data (optional)',
|
|
2043
|
+
items: [
|
|
2044
|
+
'Review the connections suggested for you',
|
|
2045
|
+
'Connect the ones that add value, e.g. customer names on invoices',
|
|
2046
|
+
'Connected data provides extra fields at the next step',
|
|
2047
|
+
'Skip this step if the main data source has everything you need',
|
|
2048
|
+
],
|
|
2049
|
+
}) +
|
|
2050
|
+
helpPanel({
|
|
2051
|
+
bg: '#eff6ff',
|
|
2052
|
+
border: '#3b82f6',
|
|
2053
|
+
text: '#1e3a8a',
|
|
2054
|
+
icon: 'columns',
|
|
2055
|
+
title: 'Step 3: Choose Information',
|
|
2056
|
+
items: [
|
|
2057
|
+
'Tick the fields you want to see, from your main data source and anything you connected',
|
|
2058
|
+
'Fields are grouped by category to make them easier to find',
|
|
2059
|
+
'Use "Select All Visible" or "Clear All" to work quickly',
|
|
2060
|
+
],
|
|
2061
|
+
}) +
|
|
2062
|
+
helpPanel({
|
|
2063
|
+
bg: '#fdf2f8',
|
|
2064
|
+
border: '#ec4899',
|
|
2065
|
+
text: '#9d174d',
|
|
2066
|
+
icon: 'filter',
|
|
2067
|
+
title: 'Step 4: Filter Results (optional)',
|
|
2068
|
+
items: [
|
|
2069
|
+
'Narrow the results down, e.g. active clients only',
|
|
2070
|
+
'Combine conditions with AND/OR logic',
|
|
2071
|
+
'Group conditions together for more involved rules',
|
|
2072
|
+
'Great for date ranges and status filters',
|
|
2073
|
+
],
|
|
2074
|
+
}) +
|
|
2075
|
+
helpPanel({
|
|
2076
|
+
bg: '#f0fdf4',
|
|
2077
|
+
border: '#22c55e',
|
|
2078
|
+
text: '#166534',
|
|
2079
|
+
icon: 'database',
|
|
2080
|
+
title: 'Step 5: Group Configuration (optional)',
|
|
2081
|
+
items: [
|
|
2082
|
+
'Turn on grouping to split the report into sections',
|
|
2083
|
+
'Choose the field to group by, e.g. status or category',
|
|
2084
|
+
'Set the group display and styling options',
|
|
2085
|
+
'Skip this step for a plain table',
|
|
2086
|
+
],
|
|
2087
|
+
}) +
|
|
2088
|
+
helpPanel({
|
|
2089
|
+
bg: '#f3e8ff',
|
|
2090
|
+
border: '#8b5cf6',
|
|
2091
|
+
text: '#6b21a8',
|
|
2092
|
+
icon: 'download',
|
|
2093
|
+
title: 'Step 6: Preview & Save',
|
|
2094
|
+
items: [
|
|
2095
|
+
'Click "Generate Report" to see your data',
|
|
2096
|
+
'Review the results and refine as needed',
|
|
2097
|
+
'Save the report so you can run it again later',
|
|
2098
|
+
'Click "Export" to download the results as an Excel file',
|
|
2099
|
+
],
|
|
2100
|
+
}),
|
|
2101
|
+
|
|
2102
|
+
helpHeading('star', '#f59e0b', 'Pro Tips') +
|
|
2103
|
+
helpPanel({
|
|
2104
|
+
bg: '#fffbeb',
|
|
2105
|
+
border: '#f59e0b',
|
|
2106
|
+
text: '#92400e',
|
|
2107
|
+
items: [
|
|
2108
|
+
'<strong>Start simple:</strong> begin with a basic report, then add to it',
|
|
2109
|
+
'<strong>Save before exporting:</strong> an export needs the report to have a name',
|
|
2110
|
+
'<strong>Save your work:</strong> a saved report can be run again any time against current data',
|
|
2111
|
+
'<strong>Date filters:</strong> narrowing the dates keeps big reports fast',
|
|
2112
|
+
'<strong>Field limits:</strong> too many fields can slow a report down',
|
|
2113
|
+
],
|
|
2114
|
+
}),
|
|
2115
|
+
|
|
2116
|
+
helpHeading('settings', '#dc2626', 'Common Issues') +
|
|
2117
|
+
helpPanel({
|
|
2118
|
+
bg: '#fef2f2',
|
|
2119
|
+
border: '#dc2626',
|
|
2120
|
+
text: '#991b1b',
|
|
2121
|
+
items: [
|
|
2122
|
+
'<strong>Report too slow?</strong> Add date filters or reduce the number of fields',
|
|
2123
|
+
'<strong>Missing data?</strong> Check the connections you added at step 2',
|
|
2124
|
+
'<strong>Export failing?</strong> Try a smaller date range or fewer rows',
|
|
2125
|
+
'<strong>No data showing?</strong> Review your filter conditions',
|
|
2126
|
+
],
|
|
2127
|
+
}),
|
|
2128
|
+
]);
|
|
2129
|
+
|
|
2130
|
+
/** The guide matches whichever wizard the user is actually looking at. */
|
|
2131
|
+
const showGuidedHelp = () =>
|
|
2132
|
+
isSemantic ? showSemanticGuidedHelp() : showLegacyGuidedHelp();
|
|
1984
2133
|
|
|
1985
2134
|
// Initialize component
|
|
1986
2135
|
useEffect(() => {
|
|
@@ -1994,12 +2143,17 @@ const GenericReportImproved = ({
|
|
|
1994
2143
|
|
|
1995
2144
|
fetchSavedReports();
|
|
1996
2145
|
|
|
1997
|
-
// Show help on first load
|
|
1998
|
-
|
|
2146
|
+
// Show help on first load. The two wizards keep separate flags: users
|
|
2147
|
+
// who already dismissed the legacy guide have never seen the semantic
|
|
2148
|
+
// one, and it describes a different set of steps.
|
|
2149
|
+
const helpSeenKey = isSemantic
|
|
2150
|
+
? 'reportBuilder_hasSeenSemanticHelp'
|
|
2151
|
+
: 'reportBuilder_hasSeenHelp';
|
|
2152
|
+
const hasSeenHelp = localStorage.getItem(helpSeenKey);
|
|
1999
2153
|
if (!hasSeenHelp) {
|
|
2000
2154
|
setTimeout(() => {
|
|
2001
2155
|
showGuidedHelp();
|
|
2002
|
-
localStorage.setItem(
|
|
2156
|
+
localStorage.setItem(helpSeenKey, 'true');
|
|
2003
2157
|
}, 500);
|
|
2004
2158
|
}
|
|
2005
2159
|
}, [tableUrl, reportsUrl, semanticStatus]); // Re-fetch when URLs change
|