From d14fc1d3969976789146d2bceda63bc0c488ddaf Mon Sep 17 00:00:00 2001 From: Ronni Skansing Date: Fri, 12 Jun 2026 09:51:54 +0200 Subject: [PATCH] add company page - improve company settings UI Signed-off-by: Ronni Skansing --- .../company/CompanyCustomStats.svelte | 385 ++++++++++++++ .../modal/CompanyReportTemplateModal.svelte | 138 +++++ frontend/src/routes/company/+page.svelte | 430 +--------------- frontend/src/routes/company/[id]/+page.svelte | 364 +++++++++++++ .../routes/company/[id]/stats/+page.svelte | 487 ------------------ 5 files changed, 891 insertions(+), 913 deletions(-) create mode 100644 frontend/src/lib/components/company/CompanyCustomStats.svelte create mode 100644 frontend/src/lib/components/modal/CompanyReportTemplateModal.svelte create mode 100644 frontend/src/routes/company/[id]/+page.svelte delete mode 100644 frontend/src/routes/company/[id]/stats/+page.svelte diff --git a/frontend/src/lib/components/company/CompanyCustomStats.svelte b/frontend/src/lib/components/company/CompanyCustomStats.svelte new file mode 100644 index 0000000..1b2d1df --- /dev/null +++ b/frontend/src/lib/components/company/CompanyCustomStats.svelte @@ -0,0 +1,385 @@ + + +

+ Manually recorded campaign results for reporting on activity run outside the platform. +

+Add + + + {#each customStats as stats} + {@const pct = getStatPercentages(stats)} + + + + + + + + + + + + + + openUpdateModal(stats.id)} /> + openDeleteAlert(stats)} /> + + + + {/each} +
+ + + + + + Campaign Name + Total Recipients + + Emails Sent + Email Opens (Read) + + + Links Clicked + Data Submissions + + Reported as Phishing + Date + + + + + + + + + onClickDelete(deleteValues.id)} + bind:isVisible={isDeleteAlertVisible} +/> diff --git a/frontend/src/lib/components/modal/CompanyReportTemplateModal.svelte b/frontend/src/lib/components/modal/CompanyReportTemplateModal.svelte new file mode 100644 index 0000000..b30f127 --- /dev/null +++ b/frontend/src/lib/components/modal/CompanyReportTemplateModal.svelte @@ -0,0 +1,138 @@ + + +{#if visible} + + +
+ + + {#if templateID} +
+ +
+ {/if} +
+ +
+
+{/if} diff --git a/frontend/src/routes/company/+page.svelte b/frontend/src/routes/company/+page.svelte index d99d390..49cc56d 100644 --- a/frontend/src/routes/company/+page.svelte +++ b/frontend/src/routes/company/+page.svelte @@ -5,7 +5,6 @@ import Headline from '$lib/components/Headline.svelte'; import TableRow from '$lib/components/table/TableRow.svelte'; import TableCell from '$lib/components/table/TableCell.svelte'; - import TableUpdateButton from '$lib/components/table/TableUpdateButton.svelte'; import TableDeleteButton from '$lib/components/table/TableDeleteButton2.svelte'; import FormError from '$lib/components/FormError.svelte'; import { addToast } from '$lib/store/toast'; @@ -20,16 +19,10 @@ import { showIsLoading, hideIsLoading } from '$lib/store/loading.js'; import TableDropDownEllipsis from '$lib/components/table/TableDropDownEllipsis.svelte'; import DeleteAlert from '$lib/components/modal/DeleteAlert.svelte'; - import TableDropDownButton from '$lib/components/table/TableDropDownButton.svelte'; import Alert from '$lib/components/Alert.svelte'; - import ScimModal from '$lib/components/modal/ScimModal.svelte'; - import Editor from '$lib/components/editor/Editor.svelte'; - import FormGrid from '$lib/components/FormGrid.svelte'; // bindings let form = null; - let companyAutoPruneEnabled = false; - let companyAutoPruneEnabledOriginal = false; const formValues = { name: null, comment: null @@ -42,8 +35,6 @@ let isModalVisible = false; let isSubmitting = false; let isTableLoading = true; - let modalMode = null; - let modalText = ''; let isDeleteAlertVisible = false; let deleteValues = { @@ -51,26 +42,7 @@ name: null }; - let isViewCommentModalVisible = false; - let viewCommentCompany = null; - - let isExportCompanyModalVisible = false; let isExportSharedModalVisible = false; - let exportCompany = null; - - let isScimModalVisible = false; - let scimCompany = null; - - let isCompanyReportTemplateModalVisible = false; - let companyReportTemplateContent = ''; - let companyReportTemplateID = null; - let companyReportTemplateError = ''; - let isCompanyReportTemplateSubmitting = false; - let activeReportTemplateCompany = null; - - $: { - modalText = modalMode === 'create' ? 'New company' : 'Update company'; - } // hooks onMount(() => { @@ -96,24 +68,6 @@ } }; - /** - * Gets a company by ID - * @param {string} id - */ - const getCompany = async (id) => { - try { - const res = await api.company.getByID(id); - if (res.success) { - return res.data; - } else { - throw res.error; - } - } catch (e) { - addToast('Failed to get company', 'Error'); - console.error('failed to get company', e); - } - }; - const getCompanies = async () => { try { const res = await api.company.getAll(tableURLParams); @@ -131,11 +85,7 @@ const onSubmit = async () => { try { isSubmitting = true; - if (modalMode === 'create') { - await create(); - } else { - await update(); - } + await create(); } finally { isSubmitting = false; } @@ -158,38 +108,6 @@ refreshCompanies(); }; - const update = async () => { - modalError = ''; - try { - const res = await api.company.update(formValues.id, formValues.name, formValues.comment); - if (!res.success) { - modalError = res.error; - return; - } - if (companyAutoPruneEnabled !== companyAutoPruneEnabledOriginal) { - await saveCompanyAutoPrune(formValues.id, companyAutoPruneEnabled); - } - addToast('Company updated', 'Success'); - closeUpdateModal(); - } catch (e) { - addToast('Failed to update company', 'Error'); - console.error('failed to update company', e); - } - refreshCompanies(); - }; - - const saveCompanyAutoPrune = async (id, enabled) => { - try { - const res = await api.company.setAutoPrune(id, enabled); - if (!res.success) { - addToast('Failed to save auto-prune setting', 'Error'); - } - } catch (e) { - addToast('Failed to save auto-prune setting', 'Error'); - console.error('failed to save company auto-prune', e); - } - }; - const openDeleteAlert = async (company) => { isDeleteAlertVisible = true; deleteValues.id = company.id; @@ -216,10 +134,7 @@ }; const openCreateModal = () => { - modalMode = 'create'; modalError = ''; - // reset form values for create mode - formValues.id = null; formValues.name = null; formValues.comment = null; isModalVisible = true; @@ -228,110 +143,20 @@ const closeModal = () => { modalError = ''; isModalVisible = false; - // reset form values - formValues.id = null; formValues.name = null; formValues.comment = null; form.reset(); }; - /** - * @param {string} id - */ - const openUpdateModal = async (id) => { - modalMode = 'update'; - try { - showIsLoading(); - const company = await getCompany(id); - formValues.id = company.id; - formValues.name = company.name; - formValues.comment = company.comment || null; - try { - const optRes = await api.company.getAutoPrune(id); - companyAutoPruneEnabled = optRes.success && optRes.data?.enabled === true; - companyAutoPruneEnabledOriginal = companyAutoPruneEnabled; - } catch (_) { - companyAutoPruneEnabled = false; - } - isModalVisible = true; - } catch (e) { - addToast('Failed to get company', 'Error'); - console.error('failed to get company', e); - } finally { - hideIsLoading(); - } - }; - - const closeUpdateModal = () => { - isModalVisible = false; - modalError = ''; - // reset form values - formValues.id = null; - formValues.name = null; - formValues.comment = null; - companyAutoPruneEnabled = false; - companyAutoPruneEnabledOriginal = false; - form.reset(); - }; - - const openViewCommentModal = (company) => { - viewCommentCompany = company; - isViewCommentModalVisible = true; - }; - - const closeViewCommentModal = () => { - isViewCommentModalVisible = false; - viewCommentCompany = null; - }; - - const openExportCompanyModal = (company) => { - exportCompany = company; - isExportCompanyModalVisible = true; - }; - - const closeExportCompanyModal = () => { - isExportCompanyModalVisible = false; - exportCompany = null; - }; - const openExportSharedModal = () => { isExportSharedModalVisible = true; }; - const closeExportSharedModal = () => { - isExportSharedModalVisible = false; - }; - - const openScimModal = (company) => { - scimCompany = company; - isScimModalVisible = true; - }; - - const closeScimModal = () => { - isScimModalVisible = false; - scimCompany = null; - }; - - const onConfirmExportCompany = async () => { - try { - showIsLoading(); - api.company.export(exportCompany.id); - closeExportCompanyModal(); - return { success: true }; - } catch (e) { - addToast('Failed to export company events', 'Error'); - console.error('failed to export company events', e); - return { success: false, error: e }; - } finally { - hideIsLoading(); - } - }; - const onConfirmExportShared = async () => { try { showIsLoading(); api.company.export(); - closeExportSharedModal(); + isExportSharedModalVisible = false; return { success: true }; } catch (e) { addToast('Failed to export shared events', 'Error'); @@ -341,90 +166,6 @@ hideIsLoading(); } }; - - const openCompanyReportTemplateModal = async (company) => { - activeReportTemplateCompany = company; - companyReportTemplateContent = ''; - companyReportTemplateID = null; - companyReportTemplateError = ''; - try { - showIsLoading(); - const response = await api.reportTemplate.getAll(company.id); - if (response.success && response.data?.rows?.length > 0) { - const tmpl = response.data.rows[0]; - companyReportTemplateContent = tmpl.content || ''; - companyReportTemplateID = tmpl.id || null; - } - } catch (error) { - console.error('Failed to load company report template:', error); - companyReportTemplateError = 'Failed to load template'; - } finally { - hideIsLoading(); - isCompanyReportTemplateModalVisible = true; - } - }; - - const closeCompanyReportTemplateModal = () => { - isCompanyReportTemplateModalVisible = false; - activeReportTemplateCompany = null; - companyReportTemplateError = ''; - }; - - const onSubmitCompanyReportTemplate = async (event) => { - const saveOnly = event?.detail?.saveOnly || false; - isCompanyReportTemplateSubmitting = true; - companyReportTemplateError = ''; - try { - let response; - if (companyReportTemplateID) { - response = await api.reportTemplate.update(companyReportTemplateID, { - content: companyReportTemplateContent - }); - } else { - response = await api.reportTemplate.create({ - content: companyReportTemplateContent, - companyID: activeReportTemplateCompany.id - }); - if (response.success && response.data?.id) { - companyReportTemplateID = response.data.id; - } - } - if (response.success) { - addToast('Report template saved', 'Success'); - if (!saveOnly) { - isCompanyReportTemplateModalVisible = false; - } - } else { - companyReportTemplateError = response.error || 'Failed to save template'; - } - } catch (error) { - console.error('Failed to save company report template:', error); - companyReportTemplateError = 'Failed to save template'; - } finally { - isCompanyReportTemplateSubmitting = false; - } - }; - - const onDeleteCompanyReportTemplate = async () => { - if (!companyReportTemplateID) return; - isCompanyReportTemplateSubmitting = true; - try { - const response = await api.reportTemplate.delete(companyReportTemplateID); - if (response.success) { - addToast('Report template deleted', 'Success'); - companyReportTemplateID = null; - companyReportTemplateContent = ''; - isCompanyReportTemplateModalVisible = false; - } else { - companyReportTemplateError = response.error || 'Failed to delete template'; - } - } catch (error) { - console.error('Failed to delete company report template:', error); - companyReportTemplateError = 'Failed to delete template'; - } finally { - isCompanyReportTemplateSubmitting = false; - } - }; @@ -445,9 +186,7 @@ - - - - - -
- {#if exportCompany} -

Are you sure you want to export all data for:

-
-

{exportCompany.name}

-
-

- This will download a ZIP file containing all company data, recipients, and campaign - events. -

- {/if} -
-
- - - - - {#if isCompanyReportTemplateModalVisible} - - -
- - - {#if companyReportTemplateID} -
- -
- {/if} -
- -
-
- {/if} diff --git a/frontend/src/routes/company/[id]/+page.svelte b/frontend/src/routes/company/[id]/+page.svelte new file mode 100644 index 0000000..77a9d09 --- /dev/null +++ b/frontend/src/routes/company/[id]/+page.svelte @@ -0,0 +1,364 @@ + + + +
+ {#if !loaded} + + {:else} + + + + +
+ {#if active === 'general'} +
+ + + Company Name +
+

Comment

+