@gnar-engine/cli 1.0.3 → 1.0.4

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.
Files changed (160) hide show
  1. package/bootstrap/deploy.localdev.yml +18 -31
  2. package/bootstrap/secrets.localdev.yml +7 -12
  3. package/bootstrap/services/user/Dockerfile +1 -1
  4. package/package.json +1 -1
  5. package/src/config.js +2 -1
  6. package/src/dev/dev.service.js +44 -16
  7. package/src/scaffolder/commands.js +11 -4
  8. package/src/scaffolder/scaffolder.handler.js +228 -55
  9. package/templates/service/Dockerfile.hbs +4 -1
  10. package/templates/service/package.json.hbs +14 -16
  11. package/templates/service/{app.js.hbs → src/app.js.hbs} +8 -4
  12. package/templates/service/{commands → src/commands}/{{serviceName}}.handler.js.hbs +1 -2
  13. package/{bootstrap/services/agent/src/config.js → templates/service/src/mongodb.config.js.hbs} +11 -18
  14. package/templates/service/{config.js.hbs → src/mysql.config.js.hbs} +6 -0
  15. package/{bootstrap/services/agent/src/schema/Agent.schema.js → templates/service/src/schema/{{serviceName}}.schema.js.hbs} +3 -3
  16. package/templates/service/src/services/mongodb.{{serviceName}}.service.js.hbs +70 -0
  17. package/bootstrap/services/agent/Dockerfile +0 -23
  18. package/bootstrap/services/agent/notes.md +0 -28
  19. package/bootstrap/services/agent/package.json +0 -16
  20. package/bootstrap/services/agent/src/app.js +0 -52
  21. package/bootstrap/services/agent/src/commands/agent.handler.js +0 -104
  22. package/bootstrap/services/agent/src/controllers/http.controller.js +0 -44
  23. package/bootstrap/services/agent/src/controllers/message.controller.js +0 -51
  24. package/bootstrap/services/agent/src/db/migrations/01-init.js +0 -50
  25. package/bootstrap/services/agent/src/db/migrations/02-agent-service-init.js +0 -36
  26. package/bootstrap/services/agent/src/policies/agent.policy.js +0 -13
  27. package/bootstrap/services/agent/src/services/agent.service.js +0 -259
  28. package/bootstrap/services/agent/src/services/chatgpt.service.js +0 -46
  29. package/bootstrap/services/agent/src/services/manifest.service.js +0 -21
  30. package/bootstrap/services/portal/Dockerfile +0 -23
  31. package/bootstrap/services/portal/Dockerfile.remote +0 -40
  32. package/bootstrap/services/portal/README.md +0 -22
  33. package/bootstrap/services/portal/nginx.conf +0 -12
  34. package/bootstrap/services/portal/package.json +0 -59
  35. package/bootstrap/services/portal/public/favicon.ico +0 -0
  36. package/bootstrap/services/portal/public/gnar-white.png +0 -0
  37. package/bootstrap/services/portal/public/gnarengine-logo-black.png +0 -0
  38. package/bootstrap/services/portal/public/index.html +0 -43
  39. package/bootstrap/services/portal/public/logo192.png +0 -0
  40. package/bootstrap/services/portal/public/logo512.png +0 -0
  41. package/bootstrap/services/portal/public/manifest.json +0 -25
  42. package/bootstrap/services/portal/public/robots.txt +0 -3
  43. package/bootstrap/services/portal/src/App.js +0 -56
  44. package/bootstrap/services/portal/src/assets/Logo_Anchord_Black.svg +0 -1
  45. package/bootstrap/services/portal/src/assets/Logo_Anchord_Black_Green.svg +0 -1
  46. package/bootstrap/services/portal/src/assets/Logo_Anchord_White_Green.svg +0 -1
  47. package/bootstrap/services/portal/src/assets/activity.svg +0 -3
  48. package/bootstrap/services/portal/src/assets/arrow.svg +0 -3
  49. package/bootstrap/services/portal/src/assets/bin-white.svg +0 -3
  50. package/bootstrap/services/portal/src/assets/bin.svg +0 -3
  51. package/bootstrap/services/portal/src/assets/check.svg +0 -3
  52. package/bootstrap/services/portal/src/assets/chevron.svg +0 -3
  53. package/bootstrap/services/portal/src/assets/contact.svg +0 -3
  54. package/bootstrap/services/portal/src/assets/dots-vertical.svg +0 -5
  55. package/bootstrap/services/portal/src/assets/eye-off.svg +0 -3
  56. package/bootstrap/services/portal/src/assets/eye.svg +0 -4
  57. package/bootstrap/services/portal/src/assets/gnar-engine-black.svg +0 -47
  58. package/bootstrap/services/portal/src/assets/gnar-engine-white.svg +0 -47
  59. package/bootstrap/services/portal/src/assets/gnar_engine.svg +0 -3
  60. package/bootstrap/services/portal/src/assets/gnarengine-logo-black.png +0 -0
  61. package/bootstrap/services/portal/src/assets/home.svg +0 -3
  62. package/bootstrap/services/portal/src/assets/link.svg +0 -3
  63. package/bootstrap/services/portal/src/assets/lock.svg +0 -3
  64. package/bootstrap/services/portal/src/assets/package.svg +0 -4
  65. package/bootstrap/services/portal/src/assets/raffle.svg +0 -3
  66. package/bootstrap/services/portal/src/assets/settings.svg +0 -4
  67. package/bootstrap/services/portal/src/assets/shopping-bag.svg +0 -3
  68. package/bootstrap/services/portal/src/assets/user-black.svg +0 -3
  69. package/bootstrap/services/portal/src/assets/user.svg +0 -3
  70. package/bootstrap/services/portal/src/assets/users.svg +0 -3
  71. package/bootstrap/services/portal/src/assets/wallet.svg +0 -3
  72. package/bootstrap/services/portal/src/css/style.css +0 -1007
  73. package/bootstrap/services/portal/src/data/data.js +0 -70
  74. package/bootstrap/services/portal/src/features/attributeFormRow/AttributeFormRow.jsx +0 -32
  75. package/bootstrap/services/portal/src/features/billingShipping/BillingShipping.jsx +0 -160
  76. package/bootstrap/services/portal/src/features/crud/crudEdit.less +0 -230
  77. package/bootstrap/services/portal/src/features/crud/crudList.less +0 -134
  78. package/bootstrap/services/portal/src/features/crud/crudPage.less +0 -31
  79. package/bootstrap/services/portal/src/features/crudContact/CrudContactList.jsx +0 -108
  80. package/bootstrap/services/portal/src/features/crudContact/CrudContactSingle.jsx +0 -243
  81. package/bootstrap/services/portal/src/features/crudOrder/CrudOrderList.jsx +0 -109
  82. package/bootstrap/services/portal/src/features/crudOrder/CrudOrderSingle.jsx +0 -315
  83. package/bootstrap/services/portal/src/features/crudProducts/CrudProductList.jsx +0 -104
  84. package/bootstrap/services/portal/src/features/crudProducts/CrudProductSingle.jsx +0 -388
  85. package/bootstrap/services/portal/src/features/crudRaffles/CrudRafflesList.jsx +0 -104
  86. package/bootstrap/services/portal/src/features/crudRaffles/CrudRafflesSingle.jsx +0 -208
  87. package/bootstrap/services/portal/src/features/crudSubscription/CrudSubscriptionList.jsx +0 -110
  88. package/bootstrap/services/portal/src/features/crudSubscription/CrudSubscriptionSingle.jsx +0 -261
  89. package/bootstrap/services/portal/src/features/crudUser/CrudUserList.jsx +0 -107
  90. package/bootstrap/services/portal/src/features/crudUser/CrudUserSingle.jsx +0 -402
  91. package/bootstrap/services/portal/src/features/inventoryFormRow/InventoryFormRow.jsx +0 -30
  92. package/bootstrap/services/portal/src/features/lineItems/LineItems.jsx +0 -113
  93. package/bootstrap/services/portal/src/features/loginForm/LoginForm.jsx +0 -56
  94. package/bootstrap/services/portal/src/features/loginForm/loginForm.less +0 -56
  95. package/bootstrap/services/portal/src/features/notes/Notes.jsx +0 -18
  96. package/bootstrap/services/portal/src/features/passwordReset/PasswordResetForm.jsx +0 -96
  97. package/bootstrap/services/portal/src/features/passwordReset/PasswordResetRequestForm.jsx +0 -74
  98. package/bootstrap/services/portal/src/features/priceFormRow/PriceFormRow.jsx +0 -102
  99. package/bootstrap/services/portal/src/features/priceFormRow/priceFormRow.less +0 -24
  100. package/bootstrap/services/portal/src/features/raffleEntriesList/RaffleEntriesList.jsx +0 -99
  101. package/bootstrap/services/portal/src/features/raffleProductFormRow/RaffleProductFormRow.jsx +0 -46
  102. package/bootstrap/services/portal/src/features/sidebar/Sidebar.jsx +0 -64
  103. package/bootstrap/services/portal/src/features/sidebar/sidebar.less +0 -49
  104. package/bootstrap/services/portal/src/features/skus/Skus.jsx +0 -109
  105. package/bootstrap/services/portal/src/features/subscriptionSchedule/SubscriptionSchedule.jsx +0 -44
  106. package/bootstrap/services/portal/src/features/taxonomyFormRow/TaxonomyFormRow.jsx +0 -32
  107. package/bootstrap/services/portal/src/features/user/User.jsx +0 -54
  108. package/bootstrap/services/portal/src/features/user/user.less +0 -57
  109. package/bootstrap/services/portal/src/includes/utilities.js +0 -259
  110. package/bootstrap/services/portal/src/index.js +0 -14
  111. package/bootstrap/services/portal/src/layouts/CrudLayout.jsx +0 -50
  112. package/bootstrap/services/portal/src/layouts/LoginLayout.jsx +0 -17
  113. package/bootstrap/services/portal/src/layouts/PortalLayout.jsx +0 -48
  114. package/bootstrap/services/portal/src/layouts/loginLayout.less +0 -33
  115. package/bootstrap/services/portal/src/layouts/portalLayout.less +0 -67
  116. package/bootstrap/services/portal/src/pages/contacts/Contacts.jsx +0 -199
  117. package/bootstrap/services/portal/src/pages/dashboard/Dashboard.jsx +0 -17
  118. package/bootstrap/services/portal/src/pages/integrations/Integrations.jsx +0 -10
  119. package/bootstrap/services/portal/src/pages/login/Login.jsx +0 -15
  120. package/bootstrap/services/portal/src/pages/login/login.less +0 -10
  121. package/bootstrap/services/portal/src/pages/orders/Orders.jsx +0 -199
  122. package/bootstrap/services/portal/src/pages/passwordReset/PasswordResetPage.jsx +0 -15
  123. package/bootstrap/services/portal/src/pages/passwordResetRequest/PasswordResetRequestPage.jsx +0 -15
  124. package/bootstrap/services/portal/src/pages/payments/Payments.jsx +0 -10
  125. package/bootstrap/services/portal/src/pages/portal/Portal.jsx +0 -43
  126. package/bootstrap/services/portal/src/pages/products/Products.jsx +0 -212
  127. package/bootstrap/services/portal/src/pages/raffleEntries/RaffleEntries.jsx +0 -124
  128. package/bootstrap/services/portal/src/pages/raffles/Raffles.jsx +0 -186
  129. package/bootstrap/services/portal/src/pages/reports/Reports.jsx +0 -10
  130. package/bootstrap/services/portal/src/pages/settings/Settings.jsx +0 -10
  131. package/bootstrap/services/portal/src/pages/subscriptions/Subscriptions.jsx +0 -199
  132. package/bootstrap/services/portal/src/pages/users/Users.jsx +0 -193
  133. package/bootstrap/services/portal/src/pages/users/users.less +0 -25
  134. package/bootstrap/services/portal/src/slices/authSlice.js +0 -71
  135. package/bootstrap/services/portal/src/store/configureStore.js +0 -12
  136. package/bootstrap/services/portal/src/styles/global.less +0 -159
  137. package/bootstrap/services/portal/src/styles/inputs.less +0 -157
  138. package/bootstrap/services/portal/src/styles/main.less +0 -26
  139. package/bootstrap/services/portal/src/ui/collapsible/Collapsible.jsx +0 -97
  140. package/bootstrap/services/portal/src/ui/collapsible/collapsible.less +0 -23
  141. package/bootstrap/services/portal/src/ui/customCheckbox/CustomCheckbox.jsx +0 -17
  142. package/bootstrap/services/portal/src/ui/customCheckbox/customCheckbox.less +0 -42
  143. package/bootstrap/services/portal/src/ui/customMultiSelect/CustomMultiSelect.jsx +0 -63
  144. package/bootstrap/services/portal/src/ui/customMultiSelect/CustomMultiSelectPeriod.jsx +0 -63
  145. package/bootstrap/services/portal/src/ui/customSelect/CustomSelect.jsx +0 -63
  146. package/bootstrap/services/portal/src/ui/customSelect/customSelect.less +0 -92
  147. package/bootstrap/services/portal/src/ui/goBack/GoBack.jsx +0 -19
  148. package/bootstrap/services/portal/src/ui/loader/Loader.jsx +0 -12
  149. package/bootstrap/services/portal/src/ui/pagination/Pagination.jsx +0 -23
  150. package/bootstrap/services/portal/src/ui/repeater/Repeater.jsx +0 -29
  151. package/bootstrap/services/portal/src/ui/saveButton/SaveButton.jsx +0 -69
  152. package/bootstrap/services/portal/src/ui/saveButton/saveButton.less +0 -0
  153. package/bootstrap/services/user/src/db/seeders/development/02-portal-admin-user.js +0 -27
  154. package/templates/service/schema/{{serviceName}}.schema.js.hbs +0 -14
  155. /package/templates/service/{controllers → src/controllers}/http.controller.js.hbs +0 -0
  156. /package/templates/service/{controllers → src/controllers}/message.controller.js.hbs +0 -0
  157. /package/templates/service/{db → src/mysql.db}/migrations/01-init.js.hbs +0 -0
  158. /package/templates/service/{db → src/mysql.db}/migrations/02-{{lowerCase serviceName}}-service-init.js.hbs +0 -0
  159. /package/templates/service/{policies → src/policies}/{{serviceName}}.policy.js.hbs +0 -0
  160. /package/templates/service/{services/{{serviceName}}.service.js.hbs → src/services/mysql.{{serviceName}}.service.js.hbs} +0 -0
@@ -1,208 +0,0 @@
1
- import { useEffect, useState } from "react";
2
- import gnarEngine from '@gnar-engine/js-client';
3
- import SaveButton from "../../ui/saveButton/SaveButton";
4
- import Repeater from "../../ui/repeater/Repeater";
5
- import { raffleStatuses } from "../../data/data";
6
- import bin from '../../assets/bin.svg';
7
- import RaffleProductFormRow from "../raffleProductFormRow/RaffleProductFormRow";
8
- import CustomSelect from "../../ui/customSelect/CustomSelect";
9
-
10
-
11
- const CrudRafflesSingle = ({ loading, setLoading, raffle, setView, refreshSelectedRaffle, setRaffle, formatDate, setSelectedSingleItemId, fetchRaffles }) => {
12
- const initialForm = {
13
- name: '',
14
- status: { id: 'draft', status: 'Draft' }, // default to draft status
15
- description: '',
16
- prizeDescription: '',
17
- raffleProducts: [
18
- { productSku: '', type: '', numEntries: '' }
19
- ]
20
- };
21
-
22
- const [formData, setFormData] = useState(initialForm);
23
- const [validationErrors, setValidationErrors] = useState([]);
24
-
25
- // when raffle prop changes, populate form
26
- useEffect(() => {
27
- const raffleStatus = raffleStatuses.find(status => status.id === (raffle?.status || 'draft'));
28
-
29
- if (raffle && raffle.id) {
30
- setFormData({
31
- name: raffle.name || '',
32
- status: raffleStatus,
33
- description: raffle.description || '',
34
- prizeDescription: raffle.prize_description || '',
35
- raffleProducts: raffle.raffleProducts?.map(p => ({
36
- productSku: p.product_sku || '',
37
- numEntries: p.num_entries?.toString() || '',
38
- type: p.type || 'one-time'
39
- })) || [{ productSku: '', numEntries: '', type: 'one-time' }]
40
- });
41
- } else {
42
- setFormData(initialForm);
43
- }
44
- }, [raffle]);
45
-
46
-
47
- // handle change for text/textarea inputs
48
- const handleFieldChange = (field, value) => {
49
- setFormData({ ...formData, [field]: value });
50
- };
51
-
52
- const handleSubmit = async (e) => {
53
- e.preventDefault();
54
- setLoading('loading');
55
- setValidationErrors([]);
56
-
57
- // prepare payload: convert numEntries to number
58
- const payload = {
59
- name: formData.name,
60
- status: formData.status.id,
61
- description: formData.description,
62
- prizeDescription: formData.prizeDescription,
63
- raffleProducts: formData.raffleProducts.map(p => ({
64
- productSku: p.productSku,
65
- type: p.type,
66
- numEntries: Number(p.numEntries) || 1,
67
- }))
68
- };
69
-
70
-
71
- try {
72
- let response;
73
- if (raffle && raffle.id) {
74
- response = await gnarEngine.raffles.updateRaffle(raffle.id, payload);
75
- } else {
76
- response = await gnarEngine.raffles.createRaffle([payload]);
77
- }
78
-
79
- if (response.error) {
80
- setValidationErrors(response.error);
81
- setLoading('error');
82
- } else {
83
- setLoading('success');
84
- setTimeout(() => {
85
- setLoading(null)
86
- }, 3000);
87
-
88
- if (raffle && raffle.id) {
89
- refreshSelectedRaffle();
90
- } else {
91
- setRaffle(response.raffle);
92
- refreshSelectedRaffle();
93
- await fetchRaffles();
94
- setView('list');
95
- }
96
- }
97
- } catch (error) {
98
- console.error('Error saving raffle:', error);
99
- setValidationErrors(['Error saving raffle']);
100
- setLoading('error');
101
- setTimeout(() => setLoading(null), 3000);
102
- }
103
- };
104
-
105
- const handleDelete = async () => {
106
- if (!raffle?.id)
107
- return;
108
- if (window.confirm('Are you sure you want to delete this raffle?')) {
109
- try {
110
- setLoading('loading');
111
- await gnarEngine.raffles.deleteRaffle(raffle.id);
112
- setLoading('success');
113
- setTimeout(() => {
114
- setLoading(null);
115
- }, 3000);
116
-
117
- refreshSelectedRaffle();
118
- await fetchRaffles();
119
- setView('list');
120
- } catch (error) {
121
- console.error('Error deleting raffle:', error);
122
- setLoading('error');
123
- }
124
- }
125
- };
126
-
127
- return (
128
- <div className="single-edit raffle">
129
- {validationErrors.length > 0 && (
130
- <div className="error-messages">
131
- {validationErrors.map((err, i) => <p key={i}>{err}</p>)}
132
- </div>
133
- )}
134
-
135
- <div className="single-edit-header">
136
- <div className="single-edit-header-left">
137
- <p><strong>{raffle?.id ? `Raffle# ${raffle.id}` : 'Add New Raffle'}</strong></p>
138
- {raffle?.createdAt && <p>Date Added: {formatDate(raffle.createdAt)}</p>}
139
- </div>
140
- <div className="single-edit-header-right flex-row-buttons-cont">
141
- <button type="button" onClick={() => { setView('list'); setRaffle(null); setSelectedSingleItemId(null); }} className="secondaryButton">Back</button>
142
- {raffle?.id && <button type="button" onClick={handleDelete} className="secondaryButton">Delete</button>}
143
- </div>
144
- </div>
145
-
146
- <form onSubmit={handleSubmit} className="form-body">
147
- <div className="form-group">
148
- <label>Name</label>
149
- <input type="text" value={formData.name} onChange={e => handleFieldChange('name', e.target.value)} />
150
- </div>
151
-
152
- <CustomSelect
153
- name="status"
154
- placeholder="Status"
155
- options={raffleStatuses}
156
- labelKey="status"
157
- setSelectedOption={selectedItem => handleFieldChange('status', selectedItem)}
158
- selectedOption={formData.status}
159
- />
160
-
161
- <div className="form-group">
162
- <label>Description</label>
163
- <textarea value={formData.description} onChange={e => handleFieldChange('description', e.target.value)} />
164
- </div>
165
-
166
- <div className="form-group">
167
- <label>Prize Description</label>
168
- <textarea value={formData.prizeDescription} onChange={e => handleFieldChange('prizeDescription', e.target.value)} />
169
- </div>
170
-
171
- </form>
172
-
173
- <Repeater
174
- items={formData.raffleProducts}
175
- setItems={(newItems) => setFormData({ ...formData, raffleProducts: newItems })}
176
- defaultItem={{ productSku: '', type: '', numEntries: 1 }}
177
- buttonText="Add Product"
178
- renderRow={(item, index, updateItem, remove) => (
179
- <RaffleProductFormRow
180
- key={index}
181
- item={item}
182
- onChange={(field, value) => updateItem({ ...item, [field]: value })}
183
- remove={remove}
184
- />
185
- )}
186
- />
187
-
188
-
189
- <div className="form-actions">
190
- <SaveButton
191
- save={handleSubmit}
192
- loading={loading}
193
- textCreate="Add Raffle"
194
- textCreateLoading="Saving..."
195
- textCreateSuccess="Saved"
196
- textCreateError="Error"
197
- textUpdate="Save"
198
- textUpdateLoading="Updating..."
199
- textUpdateSuccess="Updated"
200
- textUpdateError="Error"
201
- isUpdating={!!raffle?.id}
202
- />
203
- </div>
204
- </div>
205
- );
206
- };
207
-
208
- export default CrudRafflesSingle;
@@ -1,110 +0,0 @@
1
- import React, { useState, useEffect } from 'react';
2
- import gnarEngine from '@gnar-engine/js-client';
3
- import CustomCheckbox from '../../ui/customCheckbox/CustomCheckbox';
4
-
5
- const CrudSubscriptionList = ({ setSelectedSingleItemId, setView, selectedSubscriptionIds, setSelectedSubscriptionIds, subscriptions, message}) => {
6
-
7
- const allSelected = subscriptions.length > 0 && selectedSubscriptionIds.size === subscriptions.length;
8
-
9
- const toggleContactSelection = (subscriptionId) => {
10
- setSelectedSubscriptionIds(prev => {
11
- const newSet = new Set(prev);
12
- if (newSet.has(subscriptionId)) {
13
- newSet.delete(subscriptionId);
14
- } else {
15
- newSet.add(subscriptionId);
16
- }
17
- return newSet;
18
- });
19
- };
20
-
21
-
22
- const toggleSelectAll = () => {
23
- if (allSelected) {
24
- setSelectedSubscriptionIds(new Set());
25
- } else {
26
- setSelectedSubscriptionIds(new Set(subscriptions.map(subscription => subscription.id)));
27
- }
28
- };
29
-
30
-
31
- const handleEditClick = (product) => {
32
- setSelectedSingleItemId(product.id);
33
- setView('single');
34
- };
35
-
36
- const columns = [
37
- { columnLabel: 'Subscription', dataKey: 'id' },
38
- { columnLabel: 'First Name', dataKey: 'firstName' },
39
- { columnLabel: 'Last Name', dataKey: 'lastName' },
40
- { columnLabel: 'Date', dataKey: 'createdAt' },
41
- { columnLabel: 'Status', dataKey: 'status' },
42
- { columnLabel: 'Total', dataKey: 'total' },
43
- { columnLabel: 'Date added', dataKey: 'createdAt' },
44
- ];
45
-
46
-
47
- return (
48
- <div className="">
49
- <div className='pagination-labels-cont'>
50
- <div className='pagination-count'>
51
- Showing {subscriptions.length} of {subscriptions.length} subscription{subscriptions.length !== 1 ? 's' : ''}
52
- </div>
53
- <div className="pagination-count">
54
- {selectedSubscriptionIds.size} of {subscriptions.length} subscription{subscriptions.length !== 1 ? 's' : ''} selected
55
- </div>
56
- </div>
57
- <div className='crud-list'>
58
- <table className='custom-table'>
59
- <thead>
60
- <tr>
61
- <th className="checkbox">
62
- <CustomCheckbox
63
- name="selectAll"
64
- checked={allSelected}
65
- setChecked={toggleSelectAll}
66
- />
67
- </th>
68
- {columns.map(column => (
69
- <th key={column.columnLabel}>{column.columnLabel}</th>
70
- ))}
71
- </tr>
72
- </thead>
73
-
74
- <tbody>
75
- {message ? (
76
- <tr>
77
- <td colSpan={columns.length + 1}>{message}</td>
78
- </tr>
79
- ) : (
80
- subscriptions.length > 0 ? (
81
- subscriptions.map(order => (
82
- <tr key={order.id} onClick={() => handleEditClick(order)}>
83
- <td>
84
- <CustomCheckbox
85
- name={`checkbox-${order.id}`}
86
- checked={selectedSubscriptionIds.has(order.id)}
87
- setChecked={() => toggleContactSelection(order.id)}
88
- />
89
- </td>
90
- {columns.map(column => (
91
- <td key={column.dataKey}>{order[column.dataKey]}</td>
92
- ))}
93
- </tr>
94
- ))
95
- ) : (
96
- <tr>
97
- <td colSpan={columns.length + 1}>No orders found</td>
98
- </tr>
99
- )
100
- )}
101
- </tbody>
102
- </table>
103
- </div>
104
- </div>
105
-
106
- );
107
-
108
- };
109
-
110
- export default CrudSubscriptionList;
@@ -1,261 +0,0 @@
1
- import { useEffect, useState } from "react";
2
- import gnarEngine from '@gnar-engine/js-client';
3
- import SaveButton from "../../ui/saveButton/SaveButton";
4
- import Repeater from "../../ui/repeater/Repeater";
5
- import Notes from "../notes/Notes";
6
- import CustomSelect from "../../ui/customSelect/CustomSelect";
7
- import { orderTypes, subscriptionStatuses } from '../../data/data';
8
- import { Link } from "react-router-dom";
9
- import BillingShipping from "../billingShipping/BillingShipping";
10
- import SubscriptionSchedule from "../subscriptionSchedule/SubscriptionSchedule";
11
- import LineItems from "../lineItems/LineItems";
12
-
13
-
14
- const CrudSubscriptionSingle = ({ loading, setLoading, subscription, setView, refreshSelectedSubscription, setSubscription, fetchSubscriptions, setSelectedSingleItemId, formatDate }) => {
15
-
16
- const [formData, setFormData] = useState({});
17
- const [validationErrors, setValidationErrors] = useState([]);
18
- const [orderType, setOrderType] = useState(null);
19
- const [orderStatus, setOrderStatus] = useState(null);
20
-
21
- useEffect(() => {
22
- if (subscription && subscription._id) {
23
- setFormData({
24
- ...subscription,
25
- });
26
-
27
- // set order type
28
- const existingOrderType = orderTypes.find(type => type.id === subscription.type);
29
- setOrderType(existingOrderType);
30
-
31
- // set order status
32
- const existingSubscriptionStatus = subscriptionStatuses.find(status => status.id === subscription.status);
33
- setOrderStatus(existingSubscriptionStatus);
34
-
35
- } else {
36
- setFormData({
37
- ...formData,
38
- userId: '',
39
- notes: [],
40
- type: null,
41
- status: null,
42
- billingAddress: {
43
- firstName: '',
44
- lastName: '',
45
- addressLine1: '',
46
- addressLine2: '',
47
- city: '',
48
- postcode: '',
49
- email: '',
50
- phone: '',
51
- },
52
- shippingAddress: {
53
- firstName: '',
54
- lastName: '',
55
- addressLine1: '',
56
- addressLine2: '',
57
- city: '',
58
- postcode: '',
59
- },
60
- lineItems: [],
61
- currency: 'GBP',
62
- subTotal: 0,
63
- shipping: 0,
64
- tax: 0,
65
- total: 0,
66
- });
67
- }
68
- }, [subscription]);
69
-
70
-
71
- const handleSubmit = async (e) => {
72
- e.preventDefault();
73
- setLoading('loading');
74
- setValidationErrors([]);
75
-
76
- try {
77
-
78
- // parse ints
79
- formData.retryAttempt = parseInt(formData.retryAttempt) || 0;
80
-
81
- if (subscription) {
82
- const response = await gnarEngine.subscription.updateSubscription(subscription._id, formData);
83
- console.log('response:', response);
84
-
85
- setLoading('success');
86
- setTimeout(() => {
87
- setLoading(null);
88
- fetchSubscriptions();
89
- refreshSelectedSubscription();
90
- }, 3000);
91
-
92
- refreshSelectedSubscription();
93
- } else {
94
-
95
- const response = await gnarEngine.subscription.createSubscription([formData]);
96
- console.log('response:', response);
97
-
98
- if (response.error) {
99
- setValidationErrors(response.error);
100
- } else {
101
- setSubscription(response.subscription);
102
- refreshSelectedSubscription();
103
- setView('list');
104
- }
105
- }
106
- }
107
- catch (error) {
108
- console.error('Error updating subscription:', error);
109
- setValidationErrors(['Error updating subscription']);
110
- setTimeout(() => {
111
- setLoading(null);
112
- }, 3000);
113
- }
114
-
115
-
116
- }
117
-
118
- // handle delete user
119
- const handleDelete = async () => {
120
- if (window.confirm('Are you sure you want to delete this subscription?')) {
121
- try {
122
- setLoading('loading');
123
-
124
- await gnarEngine.subscription.deleteSubscription(subscription._id);
125
-
126
- setLoading('success');
127
- setTimeout(() => {
128
- setLoading(null);
129
- }, 3000);
130
-
131
- refreshSelectedSubscription();
132
- setView('list');
133
-
134
- } catch (error) {
135
-
136
- setLoading('error');
137
- console.error('Error deleting subscription:', subscription);
138
- }
139
- } else {
140
- console.log('Deletion canceled');
141
- }
142
- };
143
-
144
- // check order being passed in
145
- useEffect(() => {
146
- console.log('subscription:', subscription);
147
- }, [subscription]);
148
-
149
-
150
- const handleStatusChange = (selectedOption) => {
151
- setOrderStatus(selectedOption);
152
- setFormData({
153
- ...formData,
154
- status: selectedOption.id,
155
- });
156
- }
157
-
158
-
159
- return (
160
-
161
- <div className="single-edit subscriptions">
162
- {validationErrors.length > 0 &&
163
- <div className="error-messages">
164
- {validationErrors.map((error, index) => {
165
- return <p key={index}>{error}</p>
166
- })}
167
- </div>
168
- }
169
-
170
- <div className='single-edit-header'>
171
- <div className='single-edit-header-left'>
172
- <p><strong>{subscription ? 'Subscription ID# ' + subscription._id : 'Add New Subscription'}</strong></p>
173
- <p>Date Added: {formatDate(subscription?.createdAt)}</p>
174
- <label htmlFor="orderStatus">Order Status</label>
175
- <CustomSelect
176
- name="status"
177
- labelKey="status"
178
- placeholder="Select subscription status"
179
- options={subscriptionStatuses}
180
- setSelectedOption={handleStatusChange}
181
- selectedOption={orderStatus}
182
- />
183
- <div className="input-cont flex-row flex-row-end">
184
- <div>
185
- <label htmlFor="userId">User ID</label>
186
- <input
187
- type="text"
188
- name="userId"
189
- placeholder="User ID"
190
- value={formData.userId}
191
- onChange={(e) => setFormData({ ...formData, userId: e.target.value })}
192
- />
193
- </div>
194
- <Link to={`/portal/users?view=single&id=${subscription?.userId}`}>
195
- <button className="mainButton">View / Edit</button>
196
- </Link>
197
- </div>
198
-
199
- </div>
200
- <div className='single-edit-header-right'>
201
- <div className="flex-row-buttons-cont">
202
- <button onClick={() => {
203
- setView('list');
204
- setSubscription(null);
205
- setSelectedSingleItemId(null);
206
- }} className="secondaryButton">
207
- Back
208
- </button>
209
- <button onClick={handleDelete} className="secondaryButton">Delete</button>
210
- <SaveButton
211
- save={handleSubmit}
212
- loading={loading}
213
- textCreate="Add Subscription"
214
- textCreateLoading="Saving..."
215
- textCreateSuccess="Saved"
216
- textCreateError="Error"
217
- textUpdate="Save"
218
- textUpdateLoading="Updating..."
219
- textUpdateSuccess="Updated"
220
- textUpdateError="Error"
221
- isUpdating={!!subscription}
222
- />
223
- </div>
224
- </div>
225
- </div>
226
-
227
- <BillingShipping
228
- order={subscription}
229
- />
230
-
231
- <SubscriptionSchedule
232
- subscription={subscription}
233
- formData={formData}
234
- onChange={(e) => setFormData({ ...formData, [e.target.name]: e.target.value })}
235
- />
236
-
237
- <LineItems
238
- order={subscription}
239
- />
240
-
241
- <div className="card">
242
- <div className='card-header'>
243
- <h2>Orders</h2>
244
- </div>
245
- <div className='card-content'>
246
- <div className="subscription-details-cont">
247
- <p><strong>Parent Order ID:</strong> {subscription?.originalSubscriptionOrderId}</p>
248
- <Link to={`/portal/orders?view=single&id=${subscription?.originalSubscriptionOrderId}`}>
249
- <button className="secondaryButton">View / Edit</button>
250
- </Link>
251
- </div>
252
- </div>
253
- </div>
254
-
255
- </div>
256
-
257
- );
258
-
259
- };
260
-
261
- export default CrudSubscriptionSingle;
@@ -1,107 +0,0 @@
1
- import React, { useState, useEffect } from 'react';
2
- import gnarEngine from '@gnar-engine/js-client';
3
- import dotsVertical from '../../assets/dots-vertical.svg';
4
- import CustomCheckbox from '../../ui/customCheckbox/CustomCheckbox';
5
-
6
- const CrudUserList = ({ setSelectedSingleItemId, setView, selectedUserIds, setSelectedUserIds, users, message }) => {
7
-
8
- const allSelected = users.length > 0 && selectedUserIds.size === users.length;
9
-
10
- const handleEditClick = (user) => {
11
- setSelectedSingleItemId(user.id);
12
- setView('single');
13
- };
14
-
15
- const toggleUserSelection = (userId) => {
16
- setSelectedUserIds(prev => {
17
- const newSet = new Set(prev);
18
- if (newSet.has(userId)) {
19
- newSet.delete(userId);
20
- } else {
21
- newSet.add(userId);
22
- }
23
- return newSet;
24
- });
25
- };
26
-
27
-
28
- const toggleSelectAll = () => {
29
- if (allSelected) {
30
- setSelectedUserIds(new Set());
31
- } else {
32
- setSelectedUserIds(new Set(users.map(user => user.id)));
33
- }
34
- };
35
-
36
-
37
- const columns = [
38
- { columnLabel: 'ID', dataKey: 'id' },
39
- { columnLabel: 'Username', dataKey: 'username' },
40
- { columnLabel: 'Email', dataKey: 'email' },
41
- { columnLabel: 'User Role', dataKey: 'userRole' },
42
- { columnLabel: 'Date Added', dataKey: 'createdAt' }
43
- ];
44
-
45
- return (
46
- <div className="">
47
- <div className='pagination-labels-cont'>
48
- <div className='pagination-count'>
49
- Showing {users.length} of {users.length} user{users.length !== 1 ? 's' : ''}
50
- </div>
51
- <div className="pagination-count">
52
- {selectedUserIds.size} of {users.length} user{users.length !== 1 ? 's' : ''} selected
53
- </div>
54
- </div>
55
-
56
- <div className='crud-list'>
57
- <table className='custom-table'>
58
- <thead>
59
- <tr>
60
- <th className="checkbox">
61
- <CustomCheckbox
62
- name="select-all"
63
- checked={allSelected}
64
- setChecked={toggleSelectAll}
65
- />
66
- </th>
67
- {columns.map(column => (
68
- <th key={column.columnLabel}>{column.columnLabel}</th>
69
- ))}
70
- </tr>
71
- </thead>
72
-
73
- <tbody>
74
- {message ? (
75
- <tr>
76
- <td colSpan={columns.length + 1}>{message}</td>
77
- </tr>
78
- ) : (
79
- users.length > 0 ? (
80
- users.map(user => (
81
- <tr key={user.id} onClick={() => handleEditClick(user)}>
82
- <td onClick={(e) => e.stopPropagation()}>
83
- <CustomCheckbox
84
- name={`checkbox-${user.id}`}
85
- checked={selectedUserIds.has(user.id)}
86
- setChecked={() => toggleUserSelection(user.id)}
87
- />
88
- </td>
89
- {columns.map(column => (
90
- <td key={column.dataKey}>{user[column.dataKey]}</td>
91
- ))}
92
- </tr>
93
- ))
94
- ) : (
95
- <tr>
96
- <td colSpan={columns.length + 1}>No users found</td>
97
- </tr>
98
- )
99
- )}
100
- </tbody>
101
- </table>
102
- </div>
103
- </div>
104
- );
105
- };
106
-
107
- export default CrudUserList;