@goweekdays/layer-common 1.5.3 → 1.5.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.
- package/CHANGELOG.md +6 -0
- package/composables/useSubscription.ts +56 -15
- package/composables/useUtils.ts +167 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -34,20 +34,6 @@ export default function useSubscription() {
|
|
|
34
34
|
);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
function updateSeatById({ id = "", seats = 0, amount = 0, user = "" } = {}) {
|
|
38
|
-
return useNuxtApp().$api<Record<string, any>>(
|
|
39
|
-
`/api/subscriptions/id/${id}/seats`,
|
|
40
|
-
{
|
|
41
|
-
method: "PATCH",
|
|
42
|
-
body: {
|
|
43
|
-
seats,
|
|
44
|
-
amount,
|
|
45
|
-
user,
|
|
46
|
-
},
|
|
47
|
-
}
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
37
|
function getAll({ page = 1, limit = 20, search = "", status = "" } = {}) {
|
|
52
38
|
return useNuxtApp().$api<Record<string, any>>(`/api/subscriptions`, {
|
|
53
39
|
method: "GET",
|
|
@@ -60,11 +46,66 @@ export default function useSubscription() {
|
|
|
60
46
|
});
|
|
61
47
|
}
|
|
62
48
|
|
|
49
|
+
function computeFee(value: {
|
|
50
|
+
seats: number;
|
|
51
|
+
promoCode?: string;
|
|
52
|
+
org: string;
|
|
53
|
+
plan: string;
|
|
54
|
+
}) {
|
|
55
|
+
return useNuxtApp().$api<Record<string, any>>(
|
|
56
|
+
`/api/subscriptions/compute`,
|
|
57
|
+
{
|
|
58
|
+
method: "POST",
|
|
59
|
+
body: value,
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function subscribe(value: {
|
|
65
|
+
seats: number;
|
|
66
|
+
promoCode?: string;
|
|
67
|
+
org: string;
|
|
68
|
+
plan: string;
|
|
69
|
+
user: string;
|
|
70
|
+
}) {
|
|
71
|
+
return useNuxtApp().$api<Record<string, any>>(`/api/subscriptions`, {
|
|
72
|
+
method: "POST",
|
|
73
|
+
body: value,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function updateSeats(value: {
|
|
78
|
+
seats: number;
|
|
79
|
+
promoCode?: string;
|
|
80
|
+
org: string;
|
|
81
|
+
plan: string;
|
|
82
|
+
user: string;
|
|
83
|
+
}) {
|
|
84
|
+
return useNuxtApp().$api<Record<string, any>>(`/api/subscriptions`, {
|
|
85
|
+
method: "PATCH",
|
|
86
|
+
body: value,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function updatePromoCode(value: {
|
|
91
|
+
promoCode: string;
|
|
92
|
+
org: string;
|
|
93
|
+
user: string;
|
|
94
|
+
}) {
|
|
95
|
+
return useNuxtApp().$api<Record<string, any>>(`/api/subscriptions/promo`, {
|
|
96
|
+
method: "PATCH",
|
|
97
|
+
body: value,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
63
101
|
return {
|
|
64
102
|
subscription,
|
|
103
|
+
computeFee,
|
|
104
|
+
subscribe,
|
|
105
|
+
updateSeats,
|
|
106
|
+
updatePromoCode,
|
|
65
107
|
getAll,
|
|
66
108
|
getByOrg,
|
|
67
109
|
getTransactionsById,
|
|
68
|
-
updateSeatById,
|
|
69
110
|
};
|
|
70
111
|
}
|
package/composables/useUtils.ts
CHANGED
|
@@ -81,6 +81,12 @@ export default function useUtils() {
|
|
|
81
81
|
);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
function requireSlug(text: string) {
|
|
85
|
+
// Allows lowercase letters, dots, underscores, numbers and hyphens
|
|
86
|
+
const pattern = /^[a-z0-9._-]+$/;
|
|
87
|
+
return pattern.test(text) || "Invalid value";
|
|
88
|
+
}
|
|
89
|
+
|
|
84
90
|
function back() {
|
|
85
91
|
useRouter().back();
|
|
86
92
|
}
|
|
@@ -287,6 +293,164 @@ export default function useUtils() {
|
|
|
287
293
|
.find((part) => part.type === "currency")!.value;
|
|
288
294
|
}
|
|
289
295
|
|
|
296
|
+
/* ============================================================
|
|
297
|
+
Payment Promo Code Generator (Strict TypeScript)
|
|
298
|
+
Format:
|
|
299
|
+
PREFIX-BRAND-WORD-NUMBER-CHECK
|
|
300
|
+
|
|
301
|
+
Type → Prefix mapping:
|
|
302
|
+
fixed → FIX
|
|
303
|
+
flat → FLAT
|
|
304
|
+
volume → VOL
|
|
305
|
+
|
|
306
|
+
Example:
|
|
307
|
+
FIX-COCO-PREMIUM-742-K
|
|
308
|
+
============================================================ */
|
|
309
|
+
|
|
310
|
+
/* -------------------- Types -------------------- */
|
|
311
|
+
|
|
312
|
+
type NonEmptyString = string & { readonly __brand: unique symbol };
|
|
313
|
+
|
|
314
|
+
type PromoType = "fixed" | "flat" | "volume";
|
|
315
|
+
|
|
316
|
+
type PaymentPromoOptions = Readonly<{
|
|
317
|
+
type: PromoType;
|
|
318
|
+
brandLength?: number;
|
|
319
|
+
numericLength?: number;
|
|
320
|
+
}>;
|
|
321
|
+
|
|
322
|
+
/* -------------------- Type → Prefix Map -------------------- */
|
|
323
|
+
|
|
324
|
+
const TYPE_PREFIX: Record<PromoType, string> = {
|
|
325
|
+
fixed: "FIX",
|
|
326
|
+
flat: "FLAT",
|
|
327
|
+
volume: "VOL",
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
/* -------------------- Business Word Bank -------------------- */
|
|
331
|
+
|
|
332
|
+
const WORDS = [
|
|
333
|
+
"PRIME",
|
|
334
|
+
"STANDARD",
|
|
335
|
+
"SELECT",
|
|
336
|
+
"CORE",
|
|
337
|
+
"PLUS",
|
|
338
|
+
"ADVANTAGE",
|
|
339
|
+
"PREMIUM",
|
|
340
|
+
"BASIC",
|
|
341
|
+
"ENTERPRISE",
|
|
342
|
+
"BUSINESS",
|
|
343
|
+
"PRO",
|
|
344
|
+
"VALUE",
|
|
345
|
+
"GOLD",
|
|
346
|
+
"SILVER",
|
|
347
|
+
"PLATINUM",
|
|
348
|
+
"ACCESS",
|
|
349
|
+
"PARTNER",
|
|
350
|
+
"PREFERRED",
|
|
351
|
+
"ELITE",
|
|
352
|
+
"ESSENTIAL",
|
|
353
|
+
"ADVANCE",
|
|
354
|
+
"MAX",
|
|
355
|
+
"OPTIMAL",
|
|
356
|
+
"GROWTH",
|
|
357
|
+
"SECURE",
|
|
358
|
+
"TRUST",
|
|
359
|
+
] as const;
|
|
360
|
+
|
|
361
|
+
type PromoWord = (typeof WORDS)[number];
|
|
362
|
+
|
|
363
|
+
/* -------------------- Guards -------------------- */
|
|
364
|
+
|
|
365
|
+
function assertNonEmptyString(
|
|
366
|
+
value: unknown
|
|
367
|
+
): asserts value is NonEmptyString {
|
|
368
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
369
|
+
throw new Error("Promo base must be a non-empty string");
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/* -------------------- Utilities -------------------- */
|
|
374
|
+
|
|
375
|
+
function normalizeBase(input: NonEmptyString): string {
|
|
376
|
+
return input
|
|
377
|
+
.toUpperCase()
|
|
378
|
+
.replace(/\s+/g, "")
|
|
379
|
+
.replace(/[^A-Z0-9]/g, "");
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function randomFrom<T>(arr: readonly T[]): T {
|
|
383
|
+
return arr[Math.floor(Math.random() * arr.length)];
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function numericEntropy(length: number): string {
|
|
387
|
+
const seed = `${Date.now()}${Math.random()}`.replace(/\D/g, "");
|
|
388
|
+
return seed.slice(-length).padStart(length, "0");
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Lightweight checksum
|
|
393
|
+
* Detects tampering / typos
|
|
394
|
+
* Not cryptographic by design
|
|
395
|
+
*/
|
|
396
|
+
function checksum(value: string): string {
|
|
397
|
+
let sum = 0;
|
|
398
|
+
for (let i = 0; i < value.length; i++) {
|
|
399
|
+
sum += value.charCodeAt(i);
|
|
400
|
+
}
|
|
401
|
+
return String.fromCharCode(65 + (sum % 26));
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/* -------------------- Generator -------------------- */
|
|
405
|
+
|
|
406
|
+
function generatePaymentPromoCode(
|
|
407
|
+
base: unknown,
|
|
408
|
+
options: PaymentPromoOptions
|
|
409
|
+
): string {
|
|
410
|
+
if (base === undefined || base === null) {
|
|
411
|
+
return "";
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// if no type return empty string
|
|
415
|
+
if (!options.type) {
|
|
416
|
+
return "";
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
assertNonEmptyString(base);
|
|
420
|
+
|
|
421
|
+
const { type, brandLength = 4, numericLength = 3 } = options;
|
|
422
|
+
|
|
423
|
+
const prefix = TYPE_PREFIX[type];
|
|
424
|
+
const normalized = normalizeBase(base);
|
|
425
|
+
|
|
426
|
+
const brand = normalized.slice(0, brandLength).padEnd(brandLength, "X");
|
|
427
|
+
|
|
428
|
+
const word: PromoWord = randomFrom(WORDS);
|
|
429
|
+
const number = numericEntropy(numericLength);
|
|
430
|
+
|
|
431
|
+
const core = `${prefix}-${brand}-${word}-${number}`;
|
|
432
|
+
const check = checksum(core);
|
|
433
|
+
|
|
434
|
+
return `${core}-${check}`;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function copyToClipboard(value: string) {
|
|
438
|
+
if (!value) return;
|
|
439
|
+
if (!navigator.clipboard) {
|
|
440
|
+
console.error("Clipboard API not supported");
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
navigator.clipboard
|
|
445
|
+
.writeText(value)
|
|
446
|
+
.then(() => {
|
|
447
|
+
console.log("Copied to clipboard");
|
|
448
|
+
})
|
|
449
|
+
.catch((err) => {
|
|
450
|
+
console.error("Failed to copy:", err);
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
|
|
290
454
|
return {
|
|
291
455
|
requiredRule,
|
|
292
456
|
emailRule,
|
|
@@ -315,5 +479,8 @@ export default function useUtils() {
|
|
|
315
479
|
positiveNumberRule,
|
|
316
480
|
validateKey,
|
|
317
481
|
getCurrencySymbol,
|
|
482
|
+
requireSlug,
|
|
483
|
+
generatePaymentPromoCode,
|
|
484
|
+
copyToClipboard,
|
|
318
485
|
};
|
|
319
486
|
}
|