Skip to content

Commit ed17647

Browse files
authored
Merge pull request #162 from marmelab/user-config
Add Settings page
2 parents ff1d3ac + 137deb5 commit ed17647

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1334
-535
lines changed

doc/astro.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ export default defineConfig({
8686
label: "Users Documentation",
8787
items: [
8888
"users/user-management",
89+
"users/settings",
8990
"users/import-data",
9091
"users/merging-contacts",
9192
"users/inbound-email",

doc/src/content/docs/developers/customizing.mdx

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ title: Configuration
33
description: This document explains how to customize the Atomic CRM application.
44
---
55

6-
Developers can customize the Atomic CRM application to suit their business needs. Some of the customizations can be achieved via configuration on the `<CRM>` component, while others require changes to the source code.
6+
Admin users can already customize the application domain-specific data (e.g., deal stages, note statuses, etc.) via [the Settings page](../user//settings). However, developers can go further and define the defaults for these data by configuring the `<CRM>` component in `src/App.tsx`.
7+
8+
Other customizations require changes to the source code.
79

810
## The `<CRM>` component
911

@@ -26,12 +28,14 @@ import { CRM } from "@/components/atomic-crm/root/CRM";
2628

2729
const App = () => (
2830
<CRM
29-
contactGender={[
30-
{ value: 'male', label: 'He' },
31-
{ value: 'female', label: 'She' },
31+
companySectors={[
32+
{ value: 'technology', label: 'Technology' },
33+
{ value: 'finance', label: 'Finance' },
34+
]}
35+
dealCategories={[
36+
{ value: 'copywriting', label: 'Copywriting' },
37+
{ value: 'design', label: 'Design' },
3238
]}
33-
companySectors={['Technology', 'Finance']}
34-
dealCategories={['Copywriting', 'Design']}
3539
dealPipelineStatuses={['won']}
3640
dealStages={[
3741
{ value: 'opportunity', label: 'Opportunity' },
@@ -44,7 +48,11 @@ const App = () => (
4448
{ value: 'warm', label: 'Warm', color: '#e8cb7d' },
4549
{ value: 'hot', label: 'Hot', color: '#e88b7d' },
4650
]}
47-
taskTypes={['Call', 'Email', 'Meeting']}
51+
taskTypes={[
52+
{ value: 'call', label: 'Call' },
53+
{ value: 'email', label: 'Email' },
54+
{ value: 'meeting', label: 'Meeting' },
55+
]}
4856
/>
4957
);
5058

@@ -55,16 +63,15 @@ export default App;
5563

5664
| Props | Description | Type |
5765
|-------------------------|-----------------------------------------------------------------------|-----------------|
58-
| `contactGender` | The gender options for contacts used in the application. | ContactGender[] |
59-
| `companySectors` | The list of company sectors used in the application. | string[] |
66+
| `companySectors` | The list of company sectors used in the application. | LabeledValue[] |
6067
| `darkTheme` | The theme to use when the application is in dark mode. | RaThemeOptions |
61-
| `dealCategories` | The categories of deals used in the application. | string[] |
68+
| `dealCategories` | The categories of deals used in the application. | LabeledValue[] |
6269
| `dealPipelineStatuses` | The statuses of deals in the pipeline used in the application | string[] |
6370
| `dealStages` | The stages of deals used in the application. | DealStage[] |
6471
| `lightTheme` | The theme to use when the application is in light mode. | RaThemeOptions |
6572
| `logo` | The logo used in the CRM application. | string |
6673
| `noteStatuses` | The statuses of notes used in the application. | NoteStatus[] |
67-
| `taskTypes` | The types of tasks used in the application. | string[] |
74+
| `taskTypes` | The types of tasks used in the application. | LabeledValue[] |
6875
| `title` | The title of the CRM application. | string |
6976

7077
## Disabling Telemetry

doc/src/content/docs/index.mdx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,16 @@ import { CRM } from "@/components/atomic-crm/root/CRM";
102102
const App = () => (
103103
<CRM
104104
title="Acme CRM"
105-
taskTypes={['Call', 'Email', 'Meeting']}
106-
dealCategories={['eCommerce', 'SaaS', 'Consulting']}
105+
taskTypes={[
106+
{ value: 'call', label: 'Call' },
107+
{ value: 'email', label: 'Email' },
108+
{ value: 'meeting', label: 'Meeting' },
109+
]}
110+
dealCategories={[
111+
{ value: 'ecommerce', label: 'eCommerce' },
112+
{ value: 'saas', label: 'SaaS' },
113+
{ value: 'consulting', label: 'Consulting' },
114+
]}
107115
/>
108116
);
109117

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
title: Application Settings
3+
description: This document explains how to configure Atomic CRM.
4+
---
5+
6+
Admin users can configure various aspects of Atomic CRM to tailor the application to their specific needs. This includes customizing the user interface, defining categories, etc.
7+
8+
## Accessing the Settings Page
9+
10+
If you're logged in as an admin user, you can access the configuration page by clicking on your profile picture in the top right corner of the application and selecting "Settings" from the dropdown menu.
11+
12+
![Settings Page](../../images/settings.png)
13+
14+
The settings page is organized into different sections, each corresponding to a specific aspect of the application that can be configured. You can navigate between these sections using the left sidebar.
15+
16+
## Changing Application Settings
17+
18+
The Settings page lets you customize:
19+
20+
- The application name and logo
21+
- The company sectors
22+
- The stages of the deal pipeline (e.g., prospecting, negotiation, closed-won, etc.)
23+
- The deal categories
24+
- The note statuses (hot, cold, etc.)
25+
- The task types (call, email, etc.)
26+
27+
Once you save your changes, they will be immediately reflected across the application. For example, if you update the deal stages, the new stages will be available for users to drag and drop deals in the Kanban view, and they will also be available when creating or editing a deal.
28+
29+
When updating the name of an existing category (e.g., a deal stage), the new name will be applied to all existing records that belong to that category. For instance, if you rename the "Prospecting" deal stage to "Lead", all deals that were previously in the "Prospecting" stage will now be in the "Lead" stage.
77.6 KB
Loading

registry.json

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@
123123
"path": "src/components/atomic-crm/settings/SettingsPage.tsx",
124124
"type": "registry:component"
125125
},
126+
{
127+
"path": "src/components/atomic-crm/settings/ProfilePage.tsx",
128+
"type": "registry:component"
129+
},
126130
{
127131
"path": "src/components/atomic-crm/sales/index.ts",
128132
"type": "registry:component"
@@ -147,6 +151,10 @@
147151
"path": "src/components/atomic-crm/sales/SaleName.tsx",
148152
"type": "registry:component"
149153
},
154+
{
155+
"path": "src/components/atomic-crm/root/useConfigurationLoader.ts",
156+
"type": "registry:component"
157+
},
150158
{
151159
"path": "src/components/atomic-crm/root/i18nProvider.tsx",
152160
"type": "registry:component"
@@ -199,18 +207,10 @@
199207
"path": "src/components/atomic-crm/providers/fakerest/internal/transformOrFilter.ts",
200208
"type": "registry:component"
201209
},
202-
{
203-
"path": "src/components/atomic-crm/providers/fakerest/internal/transformOrFilter.spec.ts",
204-
"type": "registry:component"
205-
},
206210
{
207211
"path": "src/components/atomic-crm/providers/fakerest/internal/transformInFilter.ts",
208212
"type": "registry:component"
209213
},
210-
{
211-
"path": "src/components/atomic-crm/providers/fakerest/internal/transformInFilter.spec.ts",
212-
"type": "registry:component"
213-
},
214214
{
215215
"path": "src/components/atomic-crm/providers/fakerest/internal/transformFilter.ts",
216216
"type": "registry:component"
@@ -219,18 +219,10 @@
219219
"path": "src/components/atomic-crm/providers/fakerest/internal/transformContainsFilter.ts",
220220
"type": "registry:component"
221221
},
222-
{
223-
"path": "src/components/atomic-crm/providers/fakerest/internal/transformContainsFilter.spec.ts",
224-
"type": "registry:component"
225-
},
226222
{
227223
"path": "src/components/atomic-crm/providers/fakerest/internal/supabaseAdapter.ts",
228224
"type": "registry:component"
229225
},
230-
{
231-
"path": "src/components/atomic-crm/providers/fakerest/internal/supabaseAdapter.spec.ts",
232-
"type": "registry:component"
233-
},
234226
{
235227
"path": "src/components/atomic-crm/providers/fakerest/internal/listParser.ts",
236228
"type": "registry:component"
@@ -291,18 +283,10 @@
291283
"path": "src/components/atomic-crm/providers/commons/getContactAvatar.ts",
292284
"type": "registry:component"
293285
},
294-
{
295-
"path": "src/components/atomic-crm/providers/commons/getContactAvatar.spec.ts",
296-
"type": "registry:component"
297-
},
298286
{
299287
"path": "src/components/atomic-crm/providers/commons/getCompanyAvatar.ts",
300288
"type": "registry:component"
301289
},
302-
{
303-
"path": "src/components/atomic-crm/providers/commons/getCompanyAvatar.spec.ts",
304-
"type": "registry:component"
305-
},
306290
{
307291
"path": "src/components/atomic-crm/providers/commons/canAccess.ts",
308292
"type": "registry:component"
@@ -631,6 +615,10 @@
631615
"path": "src/components/atomic-crm/contacts/exportToVCard.ts",
632616
"type": "registry:component"
633617
},
618+
{
619+
"path": "src/components/atomic-crm/contacts/contactGender.ts",
620+
"type": "registry:component"
621+
},
634622
{
635623
"path": "src/components/atomic-crm/contacts/TagsListEdit.tsx",
636624
"type": "registry:component"

scripts/generate-registry.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,15 @@ const excludedHooks = [
1717
"useSupportCreateSuggestion.tsx",
1818
];
1919

20+
const testFilePattern = "**/*.{test,spec}.*";
21+
2022
const atomicCrmComponents = globSync(
2123
path.join(atomicCrmComponentsPath, "**", "*.ts*"),
24+
{ ignore: [testFilePattern] },
2225
);
2326
const supabaseComponents = globSync(
2427
path.join(supabaseComponentsPath, "**", "*.ts*"),
28+
{ ignore: [testFilePattern] },
2529
);
2630
const hooks = globSync(path.join(hooksPath, "**", "*.ts*")).filter((hook) => {
2731
return !excludedHooks.includes(path.basename(hook));

src/App.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { CRM } from "@/components/atomic-crm/root/CRM";
44
* Application entry point
55
*
66
* Customize Atomic CRM by passing props to the CRM component:
7-
* - contactGender
87
* - companySectors
98
* - darkTheme
109
* - dealCategories

src/components/atomic-crm/companies/CompanyAside.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { UrlField } from "@/components/admin/url-field";
1010
import { SelectField } from "@/components/admin/select-field";
1111

1212
import { AsideSection } from "../misc/AsideSection";
13+
import { useConfigurationContext } from "../root/ConfigurationContext";
1314
import { SaleName } from "../sales/SaleName";
1415
import type { Company } from "../types";
1516
import { sizes } from "./sizes";
@@ -97,17 +98,18 @@ export const CompanyInfo = ({ record }: { record: Company }) => {
9798
};
9899

99100
export const ContextInfo = ({ record }: { record: Company }) => {
101+
const { companySectors } = useConfigurationContext();
100102
if (!record.revenue && !record.id) {
101103
return null;
102104
}
103105

106+
const sectorLabel = companySectors.find(
107+
(s) => s.value === record.sector,
108+
)?.label;
109+
104110
return (
105111
<AsideSection title="Context">
106-
{record.sector && (
107-
<span>
108-
Sector: <TextField source="sector" />
109-
</span>
110-
)}
112+
{sectorLabel && <span>Sector: {sectorLabel}</span>}
111113
{record.size && (
112114
<span>
113115
Size: <SelectField source="size" choices={sizes} />

src/components/atomic-crm/companies/CompanyCard.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,20 @@ import { ReferenceManyField } from "@/components/admin/reference-many-field";
55
import { Card } from "@/components/ui/card";
66

77
import { Avatar as ContactAvatar } from "../contacts/Avatar";
8+
import { useConfigurationContext } from "../root/ConfigurationContext";
89
import type { Company } from "../types";
910
import { CompanyAvatar } from "./CompanyAvatar";
1011

1112
export const CompanyCard = (props: { record?: Company }) => {
1213
const createPath = useCreatePath();
1314
const record = useRecordContext<Company>(props);
15+
const { companySectors } = useConfigurationContext();
1416
if (!record) return null;
1517

18+
const sectorLabel = companySectors.find(
19+
(s) => s.value === record.sector,
20+
)?.label;
21+
1622
return (
1723
<Link
1824
to={createPath({
@@ -27,7 +33,7 @@ export const CompanyCard = (props: { record?: Company }) => {
2733
<CompanyAvatar />
2834
<div className="text-center mt-1">
2935
<h6 className="text-sm font-medium">{record.name}</h6>
30-
<p className="text-xs text-muted-foreground">{record.sector}</p>
36+
<p className="text-xs text-muted-foreground">{sectorLabel}</p>
3137
</div>
3238
</div>
3339
<div className="flex flex-row w-full justify-between gap-2">

0 commit comments

Comments
 (0)