Skip to content

Commit de04be6

Browse files
authored
Initial commit
0 parents  commit de04be6

File tree

272 files changed

+25554
-0
lines changed

Some content is hidden

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

272 files changed

+25554
-0
lines changed

.directus/README.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
The .directus directory holds a sample Docker Compose file that you can use to quickly spin up a local version of
2+
AgencyOS.
3+
4+
It also contains a `run-scripts` with some of the Run Script operation scripts using in the Directus instance > Flows >
5+
Operations.

.directus/docker-compose.yaml

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
version: '3'
2+
services:
3+
database:
4+
image: postgis/postgis:13-master
5+
# Required when running on platform other than amd64, like Apple M1/M2:
6+
# platform: linux/amd64
7+
ports:
8+
- 5432:5432
9+
volumes:
10+
- ./data/database:/var/lib/postgresql/data
11+
environment:
12+
POSTGRES_USER: 'directus'
13+
POSTGRES_PASSWORD: 'directus'
14+
POSTGRES_DB: 'directus'
15+
16+
cache:
17+
image: redis:6
18+
19+
directus:
20+
image: directus/directus:10.13.1
21+
ports:
22+
- 8055:8055
23+
volumes:
24+
- ./uploads:/directus/uploads
25+
# If you want to load extensions from the host
26+
- ./extensions:/directus/extensions
27+
depends_on:
28+
- cache
29+
- database
30+
environment:
31+
KEY: '255d861b-5ea1-5996-9aa3-922530ec40b1'
32+
SECRET: '6116487b-cda1-52c2-b5b5-c8022c45e263'
33+
34+
DB_CLIENT: 'pg'
35+
DB_HOST: 'database'
36+
DB_PORT: '5432'
37+
DB_DATABASE: 'directus'
38+
DB_USER: 'directus'
39+
DB_PASSWORD: 'directus'
40+
41+
CACHE_ENABLED: 'false'
42+
CACHE_STORE: 'redis'
43+
REDIS: 'redis://cache:6379'
44+
45+
ADMIN_EMAIL: '[email protected]'
46+
ADMIN_PASSWORD: 'd1r3ctu5'
47+
48+
# These is helpful for local developement but should probably be removed in production
49+
CORS_ENABLED: 'true'
50+
REFRESH_TOKEN_COOKIE_DOMAIN: 'localhost'
51+
EXTENSIONS_AUTO_RELOAD: 'true'
52+
53+
WEBSOCKETS_ENABLED: 'true'
54+
# The default config prevents importing files from 0.0.0.0. See https://docs.directus.io/self-hosted/config-options.html#security . This can be removed in production but in local development it is recommended to keep it so you can import logos from Organization > website.
55+
IMPORT_IP_DENY_LIST: ''
56+
57+
# Make sure to set this in production
58+
# (see https://docs.directus.io/self-hosted/config-options#general)
59+
# PUBLIC_URL: 'https://directus.example.com'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
module.exports = async function (data) {
2+
const item = { ...data.invoice_items, ...data.$trigger.payload };
3+
4+
// Basic validation for unit_price and quantity
5+
if (!item.unit_price || !item.quantity) {
6+
throw new Error('Missing or invalid unit_price or quantity.');
7+
}
8+
9+
// Calculate line_amount
10+
const lineAmount = parseFloat(item.unit_price) * parseFloat(item.quantity);
11+
if (isNaN(lineAmount)) {
12+
throw new Error('Error calculating line_amount.');
13+
}
14+
item.line_amount = lineAmount;
15+
16+
// Validate and calculate tax_amount if tax_rate is provided
17+
if (item.tax_rate && item.tax_rate.rate) {
18+
const taxRateId = item.tax_rate.id;
19+
const taxAmount = (lineAmount * parseFloat(item.tax_rate.rate)) / 100;
20+
if (isNaN(taxAmount)) {
21+
throw new Error('Error calculating tax_amount.');
22+
}
23+
item.tax_amount = taxAmount;
24+
25+
delete item.tax_rate;
26+
item.tax_rate = taxRateId;
27+
} else {
28+
item.tax_amount = 0;
29+
}
30+
31+
return item;
32+
};
+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
function calculateInvoiceTotals(invoice) {
2+
if (!invoice || !Array.isArray(invoice.line_items)) {
3+
throw new Error('Invalid invoice data format.');
4+
}
5+
6+
let subtotal = 0;
7+
let totalTax = 0;
8+
9+
for (let item of invoice.line_items) {
10+
if (item.line_amount) {
11+
subtotal += parseFloat(item.line_amount);
12+
}
13+
14+
if (item.tax_amount) {
15+
totalTax += parseFloat(item.tax_amount);
16+
}
17+
}
18+
19+
let changes = {};
20+
21+
if (invoice.subtotal !== subtotal.toFixed(2)) {
22+
changes.subtotal = subtotal.toFixed(2);
23+
}
24+
25+
if (invoice.total_tax !== totalTax.toFixed(2)) {
26+
changes.total_tax = totalTax.toFixed(2);
27+
}
28+
29+
let total = (subtotal + totalTax).toFixed(2);
30+
if (invoice.total !== total) {
31+
changes.total = total;
32+
}
33+
34+
if (Object.keys(changes).length === 0) {
35+
return null; // No changes detected
36+
}
37+
38+
return changes;
39+
}
40+
41+
module.exports = async function (data) {
42+
try {
43+
const changes = calculateInvoiceTotals(data.invoice);
44+
if (changes) {
45+
return changes;
46+
} else {
47+
throw new Error('No changes necessary');
48+
}
49+
} catch (error) {
50+
throw new Error(error.message);
51+
}
52+
};
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
function extractDomain(inputUrl) {
2+
// Regular expression to extract domain from URL
3+
const regex = /^(?:https?:\/\/)?(?:www\.)?([^\/?#]+)(?:[\/?#]|$)/i;
4+
const matches = inputUrl.match(regex);
5+
6+
// Return the matched domain or undefined if not found
7+
return matches && matches[1];
8+
}
9+
10+
module.exports = function (data) {
11+
const website = data.$trigger.payload.website;
12+
13+
const domain = extractDomain(website);
14+
15+
if (!domain) {
16+
throw new Error('Unable to properly determine the domain for this website');
17+
}
18+
return domain;
19+
};
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// This function is called when used with an Event Hook - Action (Non-Blocking) - Trigger for a flow. It is used to extract the key from the trigger object because the syntax return from Directus can be different depending on the type of trigger. For example, the trigger object for a "New Item" trigger is different than the trigger object for a "New Item in View" trigger. This function is used to extract the key from the trigger object regardless of the type of trigger.
2+
3+
function extractKey(obj) {
4+
if (obj.key) {
5+
// If "key" property exists, return its value
6+
return obj.key;
7+
} else if (obj.keys && Array.isArray(obj.keys) && obj.keys.length > 0) {
8+
// If "keys" property exists, is an array, and has at least one element, return the first element
9+
return obj.keys[0];
10+
} else {
11+
// If neither condition is met, return null or throw an error
12+
throw new Error('Key not found');
13+
}
14+
}
15+
16+
module.exports = async function (data) {
17+
const key = extractKey(data.$trigger);
18+
19+
return key;
20+
};

.directus/run-scripts/interpolate.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
function interpolate(str, params) {
2+
const names = Object.keys(params);
3+
const vals = Object.values(params);
4+
return new Function(...names, `return \`${str}\`;`)(...vals);
5+
}
6+
7+
module.exports = async function (data) {
8+
const test = 'Bryant';
9+
const email = data.get_email_template[0];
10+
const body = email.body;
11+
const result = interpolate(body, { test });
12+
13+
// Do something...
14+
return result;
15+
};
+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
function validateSchemaNames(schema, fieldsArray) {
2+
const fieldNames = fieldsArray.map((field) => field.field);
3+
const invalidNames = [];
4+
5+
schema.forEach((item) => {
6+
if (item.name && !fieldNames.includes(item.name)) {
7+
invalidNames.push(item.name);
8+
}
9+
if (item.children && Array.isArray(item.children)) {
10+
item.children.forEach((child) => {
11+
if (child.name && !fieldNames.includes(child.name)) {
12+
invalidNames.push(child.name);
13+
}
14+
});
15+
}
16+
});
17+
18+
if (invalidNames.length > 0) {
19+
throw new Error(`Form schema field names don't match collection field names: ${invalidNames.join(', ')}`);
20+
}
21+
}
22+
23+
const form_schema = [
24+
{
25+
name: 'first_name',
26+
type: 'text',
27+
label: 'First Name',
28+
placeholder: 'John',
29+
help: null,
30+
validation: 'required',
31+
width: '50',
32+
},
33+
{
34+
name: 'last_name',
35+
type: 'text',
36+
label: 'Last Name',
37+
validation: 'required',
38+
width: '50',
39+
},
40+
{
41+
name: 'email',
42+
type: 'text',
43+
label: 'Email',
44+
placeholder: '[email protected]',
45+
validation: 'required',
46+
width: '100',
47+
},
48+
{
49+
name: 'organization',
50+
type: 'text',
51+
label: 'Company',
52+
help: `What's the name of your company / organization?`,
53+
width: '100',
54+
conditionalIf: '$get(first_name).value',
55+
},
56+
{
57+
name: 'signature',
58+
type: 'signature',
59+
label: 'Signature',
60+
help: `Please sign your name above.`,
61+
width: '100',
62+
validation: 'required',
63+
options: ['type', 'draw', 'upload'],
64+
},
65+
{
66+
name: 'esignature_agreement',
67+
type: 'checkbox',
68+
label: 'I agree that my electronic signature is as valid and legally binding as a handwritten signature.',
69+
validation: 'required',
70+
width: '100',
71+
},
72+
];
73+
74+
module.exports = async function (data) {
75+
validateSchemaNames(form_schema, data.get_fields);
76+
77+
return;
78+
};

.editorconfig

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
root=true
2+
3+
[*]
4+
end_of_line = lf
5+
insert_final_newline = true
6+
charset = utf-8
7+
indent_style = tab
8+
trim_trailing_whitespace = true
9+
10+
[*.{yml,yaml}]
11+
indent_style = space

.env.example

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Directus Setup for Nuxt app
2+
# Directus Cloud urls typically look like this https://your-instance.directus.app or if you're running a local instance of Directus, it will look like this http://localhost:8055 or http://0.0.0.0:8055 or http://127.0.0.1:8055/ (depending on your setup)
3+
4+
DIRECTUS_URL="https://your-instance.directus.app"
5+
DIRECTUS_SERVER_TOKEN="your_directus_server_token_for_server_only_routes"
6+
SITE_URL="http://localhost:3000"
7+
8+
# Stripe Setup (If you want to allow payments within the portal)
9+
STRIPE_SECRET_KEY=sk_test_xxxxxxxxxxxxxxx
10+
STRIPE_PUBLISHABLE_KEY=pk_xxxxxxxxxxxxxxx
11+
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxx

.eslintignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+
dist

0 commit comments

Comments
 (0)