realtimex-crm 0.5.1 → 0.5.3
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/README.md +3 -20
- package/dist/assets/{DealList-90RCBW_j.js → DealList-C_0DbLKA.js} +2 -2
- package/dist/assets/{DealList-90RCBW_j.js.map → DealList-C_0DbLKA.js.map} +1 -1
- package/dist/assets/index-C0zU8xwx.css +1 -0
- package/dist/assets/{index-CTPFYcZP.js → index-CdC59W53.js} +47 -50
- package/dist/assets/{index-CTPFYcZP.js.map → index-CdC59W53.js.map} +1 -1
- package/dist/index.html +1 -1
- package/dist/stats.html +1 -1
- package/package.json +1 -3
- package/src/components/atomic-crm/login/StartPage.tsx +5 -109
- package/src/components/atomic-crm/root/DatabaseHealthCheck.tsx +4 -2
- package/src/components/atomic-crm/setup/DatabaseSetupGuide.tsx +51 -98
- package/src/lib/database-health-check.ts +18 -27
- package/dist/assets/index-DbCBhMSJ.css +0 -1
- package/dist/edge-functions/README.md +0 -151
- package/dist/edge-functions/updatePassword.ts +0 -84
- package/dist/edge-functions/users.ts +0 -240
- package/dist/setup.sql +0 -976
- package/public/edge-functions/README.md +0 -151
- package/public/edge-functions/updatePassword.ts +0 -84
- package/public/edge-functions/users.ts +0 -240
- package/public/setup.sql +0 -976
- package/supabase/migrations/README.md +0 -98
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
// RealTimeX CRM - Users Edge Function
|
|
2
|
-
// This function handles creating and updating CRM users (sales team members)
|
|
3
|
-
//
|
|
4
|
-
// To deploy:
|
|
5
|
-
// 1. Go to Supabase Dashboard → Edge Functions
|
|
6
|
-
// 2. Click "Deploy a new function"
|
|
7
|
-
// 3. Name it: users
|
|
8
|
-
// 4. Copy and paste this entire file
|
|
9
|
-
// 5. Click "Deploy"
|
|
10
|
-
|
|
11
|
-
import { createClient } from "jsr:@supabase/supabase-js@2";
|
|
12
|
-
|
|
13
|
-
// CORS headers for API access
|
|
14
|
-
const corsHeaders = {
|
|
15
|
-
"Access-Control-Allow-Origin": "*",
|
|
16
|
-
"Access-Control-Allow-Headers":
|
|
17
|
-
"authorization, x-client-info, apikey, content-type",
|
|
18
|
-
"Access-Control-Allow-Methods": "POST, PATCH, DELETE",
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
function createErrorResponse(status: number, message: string) {
|
|
22
|
-
return new Response(JSON.stringify({ status, message }), {
|
|
23
|
-
headers: { "Content-Type": "application/json", ...corsHeaders },
|
|
24
|
-
status,
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Initialize Supabase Admin client (uses service_role key automatically)
|
|
29
|
-
const supabaseAdmin = createClient(
|
|
30
|
-
Deno.env.get("SUPABASE_URL") ?? "",
|
|
31
|
-
Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? "",
|
|
32
|
-
{
|
|
33
|
-
auth: {
|
|
34
|
-
autoRefreshToken: false,
|
|
35
|
-
persistSession: false,
|
|
36
|
-
},
|
|
37
|
-
}
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
async function updateSaleDisabled(user_id: string, disabled: boolean) {
|
|
41
|
-
return await supabaseAdmin
|
|
42
|
-
.from("sales")
|
|
43
|
-
.update({ disabled: disabled ?? false })
|
|
44
|
-
.eq("user_id", user_id);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async function updateSaleAdministrator(
|
|
48
|
-
user_id: string,
|
|
49
|
-
administrator: boolean
|
|
50
|
-
) {
|
|
51
|
-
const { data: sales, error: salesError } = await supabaseAdmin
|
|
52
|
-
.from("sales")
|
|
53
|
-
.update({ administrator })
|
|
54
|
-
.eq("user_id", user_id)
|
|
55
|
-
.select("*");
|
|
56
|
-
|
|
57
|
-
if (!sales?.length || salesError) {
|
|
58
|
-
console.error("Error updating user:", salesError);
|
|
59
|
-
throw salesError ?? new Error("Failed to update sale");
|
|
60
|
-
}
|
|
61
|
-
return sales.at(0);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async function updateSaleAvatar(user_id: string, avatar: string) {
|
|
65
|
-
const { data: sales, error: salesError } = await supabaseAdmin
|
|
66
|
-
.from("sales")
|
|
67
|
-
.update({ avatar })
|
|
68
|
-
.eq("user_id", user_id)
|
|
69
|
-
.select("*");
|
|
70
|
-
|
|
71
|
-
if (!sales?.length || salesError) {
|
|
72
|
-
console.error("Error updating user:", salesError);
|
|
73
|
-
throw salesError ?? new Error("Failed to update sale");
|
|
74
|
-
}
|
|
75
|
-
return sales.at(0);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async function inviteUser(req: Request, currentUserSale: any) {
|
|
79
|
-
const { email, password, first_name, last_name, disabled, administrator } =
|
|
80
|
-
await req.json();
|
|
81
|
-
|
|
82
|
-
if (!currentUserSale.administrator) {
|
|
83
|
-
return createErrorResponse(401, "Not Authorized");
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const { data, error: userError } = await supabaseAdmin.auth.admin.createUser({
|
|
87
|
-
email,
|
|
88
|
-
password,
|
|
89
|
-
user_metadata: { first_name, last_name },
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
const { error: emailError } =
|
|
93
|
-
await supabaseAdmin.auth.admin.inviteUserByEmail(email);
|
|
94
|
-
|
|
95
|
-
if (!data?.user || userError) {
|
|
96
|
-
console.error(`Error inviting user: user_error=${userError}`);
|
|
97
|
-
return createErrorResponse(500, "Internal Server Error");
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (!data?.user || userError || emailError) {
|
|
101
|
-
console.error(`Error inviting user, email_error=${emailError}`);
|
|
102
|
-
return createErrorResponse(500, "Failed to send invitation mail");
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
try {
|
|
106
|
-
await updateSaleDisabled(data.user.id, disabled);
|
|
107
|
-
const sale = await updateSaleAdministrator(data.user.id, administrator);
|
|
108
|
-
|
|
109
|
-
return new Response(
|
|
110
|
-
JSON.stringify({
|
|
111
|
-
data: sale,
|
|
112
|
-
}),
|
|
113
|
-
{
|
|
114
|
-
headers: { "Content-Type": "application/json", ...corsHeaders },
|
|
115
|
-
}
|
|
116
|
-
);
|
|
117
|
-
} catch (e) {
|
|
118
|
-
console.error("Error patching sale:", e);
|
|
119
|
-
return createErrorResponse(500, "Internal Server Error");
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
async function patchUser(req: Request, currentUserSale: any) {
|
|
124
|
-
const {
|
|
125
|
-
sales_id,
|
|
126
|
-
email,
|
|
127
|
-
first_name,
|
|
128
|
-
last_name,
|
|
129
|
-
avatar,
|
|
130
|
-
administrator,
|
|
131
|
-
disabled,
|
|
132
|
-
} = await req.json();
|
|
133
|
-
const { data: sale } = await supabaseAdmin
|
|
134
|
-
.from("sales")
|
|
135
|
-
.select("*")
|
|
136
|
-
.eq("id", sales_id)
|
|
137
|
-
.single();
|
|
138
|
-
|
|
139
|
-
if (!sale) {
|
|
140
|
-
return createErrorResponse(404, "Not Found");
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Users can only update their own profile unless they are an administrator
|
|
144
|
-
if (!currentUserSale.administrator && currentUserSale.id !== sale.id) {
|
|
145
|
-
return createErrorResponse(401, "Not Authorized");
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const { data, error: userError } =
|
|
149
|
-
await supabaseAdmin.auth.admin.updateUserById(sale.user_id, {
|
|
150
|
-
email,
|
|
151
|
-
ban_duration: disabled ? "87600h" : "none",
|
|
152
|
-
user_metadata: { first_name, last_name },
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
if (!data?.user || userError) {
|
|
156
|
-
console.error("Error patching user:", userError);
|
|
157
|
-
return createErrorResponse(500, "Internal Server Error");
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (avatar) {
|
|
161
|
-
await updateSaleAvatar(data.user.id, avatar);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Only administrators can update the administrator and disabled status
|
|
165
|
-
if (!currentUserSale.administrator) {
|
|
166
|
-
const { data: new_sale } = await supabaseAdmin
|
|
167
|
-
.from("sales")
|
|
168
|
-
.select("*")
|
|
169
|
-
.eq("id", sales_id)
|
|
170
|
-
.single();
|
|
171
|
-
return new Response(
|
|
172
|
-
JSON.stringify({
|
|
173
|
-
data: new_sale,
|
|
174
|
-
}),
|
|
175
|
-
{
|
|
176
|
-
headers: {
|
|
177
|
-
"Content-Type": "application/json",
|
|
178
|
-
...corsHeaders,
|
|
179
|
-
},
|
|
180
|
-
}
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
try {
|
|
185
|
-
await updateSaleDisabled(data.user.id, disabled);
|
|
186
|
-
const sale = await updateSaleAdministrator(data.user.id, administrator);
|
|
187
|
-
return new Response(
|
|
188
|
-
JSON.stringify({
|
|
189
|
-
data: sale,
|
|
190
|
-
}),
|
|
191
|
-
{
|
|
192
|
-
headers: {
|
|
193
|
-
"Content-Type": "application/json",
|
|
194
|
-
...corsHeaders,
|
|
195
|
-
},
|
|
196
|
-
}
|
|
197
|
-
);
|
|
198
|
-
} catch (e) {
|
|
199
|
-
console.error("Error patching sale:", e);
|
|
200
|
-
return createErrorResponse(500, "Internal Server Error");
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
Deno.serve(async (req: Request) => {
|
|
205
|
-
if (req.method === "OPTIONS") {
|
|
206
|
-
return new Response(null, {
|
|
207
|
-
status: 204,
|
|
208
|
-
headers: corsHeaders,
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const authHeader = req.headers.get("Authorization")!;
|
|
213
|
-
const localClient = createClient(
|
|
214
|
-
Deno.env.get("SUPABASE_URL") ?? "",
|
|
215
|
-
Deno.env.get("SUPABASE_ANON_KEY") ?? "",
|
|
216
|
-
{ global: { headers: { Authorization: authHeader } } }
|
|
217
|
-
);
|
|
218
|
-
const { data } = await localClient.auth.getUser();
|
|
219
|
-
if (!data?.user) {
|
|
220
|
-
return createErrorResponse(401, "Unauthorized");
|
|
221
|
-
}
|
|
222
|
-
const currentUserSale = await supabaseAdmin
|
|
223
|
-
.from("sales")
|
|
224
|
-
.select("*")
|
|
225
|
-
.eq("user_id", data.user.id)
|
|
226
|
-
.single();
|
|
227
|
-
|
|
228
|
-
if (!currentUserSale?.data) {
|
|
229
|
-
return createErrorResponse(401, "Unauthorized");
|
|
230
|
-
}
|
|
231
|
-
if (req.method === "POST") {
|
|
232
|
-
return inviteUser(req, currentUserSale.data);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
if (req.method === "PATCH") {
|
|
236
|
-
return patchUser(req, currentUserSale.data);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
return createErrorResponse(405, "Method Not Allowed");
|
|
240
|
-
});
|