@goweekdays/layer-common 1.5.2 → 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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # @goweekdays/layer-common
2
2
 
3
+ ## 1.5.4
4
+
5
+ ### Patch Changes
6
+
7
+ - cff30d5: Add updatePromoCode function to useSubscription
8
+
9
+ ## 1.5.3
10
+
11
+ ### Patch Changes
12
+
13
+ - 8a5737a: Remove seats property from orgSetupFee parameter
14
+
3
15
  ## 1.5.2
4
16
 
5
17
  ### Patch Changes
@@ -63,6 +63,18 @@ export default function useOrg() {
63
63
  promoCode: "",
64
64
  });
65
65
 
66
+ function getCompanies(search = "") {
67
+ return useNuxtApp().$api<Record<string, any>[]>(
68
+ "/api/organizations/company",
69
+ {
70
+ method: "GET",
71
+ query: {
72
+ search,
73
+ },
74
+ }
75
+ );
76
+ }
77
+
66
78
  return {
67
79
  org,
68
80
  add,
@@ -70,5 +82,6 @@ export default function useOrg() {
70
82
  getByUserId,
71
83
  getById,
72
84
  updateById,
85
+ getCompanies,
73
86
  };
74
87
  }
@@ -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
  }
@@ -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
  }
@@ -277,6 +283,174 @@ export default function useUtils() {
277
283
  return (v && v >= 1) || "Value must be greater or equal to 1";
278
284
  }
279
285
 
286
+ function getCurrencySymbol(currency: string): string {
287
+ if (!currency) return "";
288
+ return new Intl.NumberFormat(undefined, {
289
+ style: "currency",
290
+ currency,
291
+ })
292
+ .formatToParts(0)
293
+ .find((part) => part.type === "currency")!.value;
294
+ }
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
+
280
454
  return {
281
455
  requiredRule,
282
456
  emailRule,
@@ -304,5 +478,9 @@ export default function useUtils() {
304
478
  setRouteParams,
305
479
  positiveNumberRule,
306
480
  validateKey,
481
+ getCurrencySymbol,
482
+ requireSlug,
483
+ generatePaymentPromoCode,
484
+ copyToClipboard,
307
485
  };
308
486
  }
@@ -46,9 +46,7 @@ export default function useUser() {
46
46
  }
47
47
 
48
48
  function orgSetupFee(
49
- value: Pick<TOrg, "name" | "email" | "contact" | "createdBy"> & {
50
- seats: number;
51
- }
49
+ value: Pick<TOrg, "name" | "email" | "contact" | "createdBy">
52
50
  ) {
53
51
  return useNuxtApp().$api<Record<string, any>>(
54
52
  "/api/verifications/org-setup-fee",
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@goweekdays/layer-common",
3
3
  "license": "MIT",
4
4
  "type": "module",
5
- "version": "1.5.2",
5
+ "version": "1.5.4",
6
6
  "main": "./nuxt.config.ts",
7
7
  "publishConfig": {
8
8
  "access": "public"