@htlkg/data 0.0.20 → 0.0.21

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/dist/index.js CHANGED
@@ -563,6 +563,109 @@ async function getReservationByConfirmation(client, confirmationCode, brandId) {
563
563
  }
564
564
  }
565
565
 
566
+ // src/queries/contacts.ts
567
+ async function getContact(client, id) {
568
+ try {
569
+ const { data, errors } = await client.models.Contact.get({ id });
570
+ if (errors) {
571
+ console.error("[getContact] GraphQL errors:", errors);
572
+ return null;
573
+ }
574
+ return data;
575
+ } catch (error) {
576
+ console.error("[getContact] Error fetching contact:", error);
577
+ throw error;
578
+ }
579
+ }
580
+ async function listContacts(client, options) {
581
+ try {
582
+ const { data, errors, nextToken } = await client.models.Contact.list(options);
583
+ if (errors) {
584
+ console.error("[listContacts] GraphQL errors:", errors);
585
+ return { items: [], nextToken: void 0 };
586
+ }
587
+ return {
588
+ items: data || [],
589
+ nextToken
590
+ };
591
+ } catch (error) {
592
+ console.error("[listContacts] Error fetching contacts:", error);
593
+ throw error;
594
+ }
595
+ }
596
+ async function listContactsByBrand(client, brandId, options) {
597
+ return listContacts(client, {
598
+ filter: { brandId: { eq: brandId } },
599
+ ...options
600
+ });
601
+ }
602
+ async function getContactByEmail(client, email, brandId) {
603
+ try {
604
+ const { data, errors } = await client.models.Contact.list({
605
+ filter: {
606
+ and: [{ email: { eq: email } }, { brandId: { eq: brandId } }]
607
+ },
608
+ limit: 1
609
+ });
610
+ if (errors) {
611
+ console.error("[getContactByEmail] GraphQL errors:", errors);
612
+ return null;
613
+ }
614
+ return data?.[0];
615
+ } catch (error) {
616
+ console.error("[getContactByEmail] Error fetching contact:", error);
617
+ throw error;
618
+ }
619
+ }
620
+ async function getContactByPhone(client, phone, brandId) {
621
+ try {
622
+ const { data, errors } = await client.models.Contact.list({
623
+ filter: {
624
+ and: [{ phone: { eq: phone } }, { brandId: { eq: brandId } }]
625
+ },
626
+ limit: 1
627
+ });
628
+ if (errors) {
629
+ console.error("[getContactByPhone] GraphQL errors:", errors);
630
+ return null;
631
+ }
632
+ return data?.[0];
633
+ } catch (error) {
634
+ console.error("[getContactByPhone] Error fetching contact:", error);
635
+ throw error;
636
+ }
637
+ }
638
+ async function searchContacts(client, query2, brandId, options) {
639
+ try {
640
+ const { data, errors, nextToken } = await client.models.Contact.list({
641
+ filter: {
642
+ and: [
643
+ { brandId: { eq: brandId } },
644
+ {
645
+ or: [
646
+ { email: { contains: query2 } },
647
+ { firstName: { contains: query2 } },
648
+ { lastName: { contains: query2 } }
649
+ ]
650
+ }
651
+ ]
652
+ },
653
+ ...options
654
+ });
655
+ if (errors) {
656
+ console.error("[searchContacts] GraphQL errors:", errors);
657
+ return { items: [], nextToken: void 0 };
658
+ }
659
+ return {
660
+ items: data || [],
661
+ nextToken
662
+ };
663
+ } catch (error) {
664
+ console.error("[searchContacts] Error searching contacts:", error);
665
+ throw error;
666
+ }
667
+ }
668
+
566
669
  // src/mutations/brands.ts
567
670
  async function createBrand(client, input) {
568
671
  try {
@@ -1234,6 +1337,265 @@ async function updateReservationStatus2(client, id, newStatus) {
1234
1337
  }
1235
1338
  }
1236
1339
 
1340
+ // src/mutations/contacts.ts
1341
+ import { z } from "zod";
1342
+ var createContactSchema = z.object({
1343
+ brandId: z.string().min(1, "Brand ID is required"),
1344
+ email: z.string().email("Invalid email address"),
1345
+ phone: z.string().optional(),
1346
+ firstName: z.string().min(1, "First name is required"),
1347
+ lastName: z.string().min(1, "Last name is required"),
1348
+ locale: z.string().optional(),
1349
+ gdprConsent: z.boolean(),
1350
+ gdprConsentDate: z.string().optional(),
1351
+ marketingOptIn: z.boolean().optional(),
1352
+ preferences: z.record(z.any()).optional(),
1353
+ tags: z.array(z.string()).optional(),
1354
+ totalVisits: z.number().int().min(0).optional(),
1355
+ lastVisitDate: z.string().optional(),
1356
+ firstVisitDate: z.string().optional(),
1357
+ legacyId: z.string().optional(),
1358
+ // Audit fields
1359
+ createdAt: z.string().optional(),
1360
+ createdBy: z.string().optional(),
1361
+ updatedAt: z.string().optional(),
1362
+ updatedBy: z.string().optional()
1363
+ });
1364
+ var updateContactSchema = z.object({
1365
+ id: z.string().min(1, "Contact ID is required"),
1366
+ brandId: z.string().min(1).optional(),
1367
+ email: z.string().email("Invalid email address").optional(),
1368
+ phone: z.string().optional(),
1369
+ firstName: z.string().min(1).optional(),
1370
+ lastName: z.string().min(1).optional(),
1371
+ locale: z.string().optional(),
1372
+ gdprConsent: z.boolean().optional(),
1373
+ gdprConsentDate: z.string().optional(),
1374
+ marketingOptIn: z.boolean().optional(),
1375
+ preferences: z.record(z.any()).optional(),
1376
+ tags: z.array(z.string()).optional(),
1377
+ totalVisits: z.number().int().min(0).optional(),
1378
+ lastVisitDate: z.string().optional(),
1379
+ firstVisitDate: z.string().optional(),
1380
+ legacyId: z.string().optional(),
1381
+ // Audit fields
1382
+ updatedAt: z.string().optional(),
1383
+ updatedBy: z.string().optional(),
1384
+ deletedAt: z.string().nullable().optional(),
1385
+ deletedBy: z.string().nullable().optional()
1386
+ });
1387
+ var mergeContactsSchema = z.object({
1388
+ primaryId: z.string().min(1, "Primary contact ID is required"),
1389
+ duplicateIds: z.array(z.string().min(1)).min(1, "At least one duplicate ID is required")
1390
+ });
1391
+ var ContactValidationError = class extends Error {
1392
+ issues;
1393
+ constructor(message, issues = []) {
1394
+ super(message);
1395
+ this.name = "ContactValidationError";
1396
+ this.issues = issues;
1397
+ }
1398
+ };
1399
+ async function createContact(client, input) {
1400
+ try {
1401
+ const validationResult = createContactSchema.safeParse(input);
1402
+ if (!validationResult.success) {
1403
+ const errorMessage = validationResult.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join(", ");
1404
+ throw new ContactValidationError(
1405
+ `Validation failed: ${errorMessage}`,
1406
+ validationResult.error.issues
1407
+ );
1408
+ }
1409
+ const { data, errors } = await client.models.Contact.create(input);
1410
+ if (errors) {
1411
+ console.error("[createContact] GraphQL errors:", errors);
1412
+ return null;
1413
+ }
1414
+ return data;
1415
+ } catch (error) {
1416
+ if (error instanceof ContactValidationError) {
1417
+ console.error("[createContact] Validation error:", error.message);
1418
+ throw error;
1419
+ }
1420
+ console.error("[createContact] Error creating contact:", error);
1421
+ throw error;
1422
+ }
1423
+ }
1424
+ async function updateContact(client, input) {
1425
+ try {
1426
+ const validationResult = updateContactSchema.safeParse(input);
1427
+ if (!validationResult.success) {
1428
+ const errorMessage = validationResult.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join(", ");
1429
+ throw new ContactValidationError(
1430
+ `Validation failed: ${errorMessage}`,
1431
+ validationResult.error.issues
1432
+ );
1433
+ }
1434
+ const { data, errors } = await client.models.Contact.update(input);
1435
+ if (errors) {
1436
+ console.error("[updateContact] GraphQL errors:", errors);
1437
+ return null;
1438
+ }
1439
+ return data;
1440
+ } catch (error) {
1441
+ if (error instanceof ContactValidationError) {
1442
+ console.error("[updateContact] Validation error:", error.message);
1443
+ throw error;
1444
+ }
1445
+ console.error("[updateContact] Error updating contact:", error);
1446
+ throw error;
1447
+ }
1448
+ }
1449
+ async function softDeleteContact(client, id, deletedBy) {
1450
+ try {
1451
+ const { errors } = await client.models.Contact.update({
1452
+ id,
1453
+ deletedAt: (/* @__PURE__ */ new Date()).toISOString(),
1454
+ deletedBy
1455
+ });
1456
+ if (errors) {
1457
+ console.error("[softDeleteContact] GraphQL errors:", errors);
1458
+ return false;
1459
+ }
1460
+ return true;
1461
+ } catch (error) {
1462
+ console.error("[softDeleteContact] Error soft-deleting contact:", error);
1463
+ throw error;
1464
+ }
1465
+ }
1466
+ async function restoreContact(client, id, retentionDays = DEFAULT_SOFT_DELETE_RETENTION_DAYS) {
1467
+ try {
1468
+ const contact = await getContact(client, id);
1469
+ if (!contact) {
1470
+ console.error("[restoreContact] Contact not found");
1471
+ return { success: false, error: "Contact not found" };
1472
+ }
1473
+ const eligibility = checkRestoreEligibility(
1474
+ contact.deletedAt,
1475
+ retentionDays
1476
+ );
1477
+ if (!eligibility.canRestore) {
1478
+ const errorMsg = `Cannot restore contact. Retention period of ${retentionDays} days has expired. Item was deleted ${eligibility.daysExpired} days ago.`;
1479
+ console.error("[restoreContact]", errorMsg);
1480
+ return { success: false, error: errorMsg };
1481
+ }
1482
+ const { errors } = await client.models.Contact.update({
1483
+ id,
1484
+ deletedAt: null,
1485
+ deletedBy: null
1486
+ });
1487
+ if (errors) {
1488
+ console.error("[restoreContact] GraphQL errors:", errors);
1489
+ return { success: false, error: "Failed to restore contact" };
1490
+ }
1491
+ return { success: true };
1492
+ } catch (error) {
1493
+ console.error("[restoreContact] Error restoring contact:", error);
1494
+ throw error;
1495
+ }
1496
+ }
1497
+ async function deleteContact(client, id) {
1498
+ try {
1499
+ const { errors } = await client.models.Contact.delete({ id });
1500
+ if (errors) {
1501
+ console.error("[deleteContact] GraphQL errors:", errors);
1502
+ return false;
1503
+ }
1504
+ return true;
1505
+ } catch (error) {
1506
+ console.error("[deleteContact] Error deleting contact:", error);
1507
+ throw error;
1508
+ }
1509
+ }
1510
+ async function mergeContacts(client, input, mergedBy) {
1511
+ try {
1512
+ const validationResult = mergeContactsSchema.safeParse(input);
1513
+ if (!validationResult.success) {
1514
+ const errorMessage = validationResult.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join(", ");
1515
+ throw new ContactValidationError(
1516
+ `Validation failed: ${errorMessage}`,
1517
+ validationResult.error.issues
1518
+ );
1519
+ }
1520
+ const { primaryId, duplicateIds } = input;
1521
+ const primaryContact = await getContact(client, primaryId);
1522
+ if (!primaryContact) {
1523
+ return {
1524
+ success: false,
1525
+ error: `Primary contact not found: ${primaryId}`
1526
+ };
1527
+ }
1528
+ const duplicateContacts = [];
1529
+ for (const duplicateId of duplicateIds) {
1530
+ const duplicate = await getContact(client, duplicateId);
1531
+ if (!duplicate) {
1532
+ return {
1533
+ success: false,
1534
+ error: `Duplicate contact not found: ${duplicateId}`
1535
+ };
1536
+ }
1537
+ duplicateContacts.push(duplicate);
1538
+ }
1539
+ let totalVisits = primaryContact.totalVisits || 0;
1540
+ let firstVisitDate = primaryContact.firstVisitDate;
1541
+ let lastVisitDate = primaryContact.lastVisitDate;
1542
+ const allTags = new Set(primaryContact.tags || []);
1543
+ for (const duplicate of duplicateContacts) {
1544
+ totalVisits += duplicate.totalVisits || 0;
1545
+ if (duplicate.firstVisitDate) {
1546
+ if (!firstVisitDate || duplicate.firstVisitDate < firstVisitDate) {
1547
+ firstVisitDate = duplicate.firstVisitDate;
1548
+ }
1549
+ }
1550
+ if (duplicate.lastVisitDate) {
1551
+ if (!lastVisitDate || duplicate.lastVisitDate > lastVisitDate) {
1552
+ lastVisitDate = duplicate.lastVisitDate;
1553
+ }
1554
+ }
1555
+ if (duplicate.tags) {
1556
+ duplicate.tags.forEach((tag) => allTags.add(tag));
1557
+ }
1558
+ }
1559
+ const updateInput = {
1560
+ id: primaryId,
1561
+ totalVisits,
1562
+ firstVisitDate,
1563
+ lastVisitDate,
1564
+ tags: Array.from(allTags),
1565
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
1566
+ updatedBy: mergedBy
1567
+ };
1568
+ const updatedPrimary = await updateContact(client, updateInput);
1569
+ if (!updatedPrimary) {
1570
+ return {
1571
+ success: false,
1572
+ error: "Failed to update primary contact with merged data"
1573
+ };
1574
+ }
1575
+ const deletedIds = [];
1576
+ for (const duplicateId of duplicateIds) {
1577
+ const deleted = await softDeleteContact(client, duplicateId, mergedBy);
1578
+ if (deleted) {
1579
+ deletedIds.push(duplicateId);
1580
+ } else {
1581
+ console.error(`[mergeContacts] Failed to soft-delete duplicate: ${duplicateId}`);
1582
+ }
1583
+ }
1584
+ return {
1585
+ success: true,
1586
+ mergedContact: updatedPrimary,
1587
+ deletedIds
1588
+ };
1589
+ } catch (error) {
1590
+ if (error instanceof ContactValidationError) {
1591
+ console.error("[mergeContacts] Validation error:", error.message);
1592
+ throw error;
1593
+ }
1594
+ console.error("[mergeContacts] Error merging contacts:", error);
1595
+ throw error;
1596
+ }
1597
+ }
1598
+
1237
1599
  // src/hooks/createDataHook.ts
1238
1600
  import { ref, computed, onMounted } from "vue";
1239
1601
  function resetClientInstance() {
@@ -1244,7 +1606,7 @@ function createDataHook(config) {
1244
1606
  defaultLimit,
1245
1607
  selectionSet,
1246
1608
  transform,
1247
- buildFilter: buildFilter6,
1609
+ buildFilter: buildFilter7,
1248
1610
  computedProperties,
1249
1611
  dataPropertyName = "data"
1250
1612
  } = config;
@@ -1254,8 +1616,8 @@ function createDataHook(config) {
1254
1616
  const loading = ref(false);
1255
1617
  const error = ref(null);
1256
1618
  const getFilter = () => {
1257
- if (buildFilter6) {
1258
- return buildFilter6(options);
1619
+ if (buildFilter7) {
1620
+ return buildFilter7(options);
1259
1621
  }
1260
1622
  return baseFilter && Object.keys(baseFilter).length > 0 ? baseFilter : void 0;
1261
1623
  };
@@ -1531,6 +1893,65 @@ function useReservations(options = {}) {
1531
1893
  };
1532
1894
  }
1533
1895
 
1896
+ // src/hooks/useContacts.ts
1897
+ function buildFilter6(options) {
1898
+ const conditions = [];
1899
+ if (options.brandId) {
1900
+ conditions.push({ brandId: { eq: options.brandId } });
1901
+ }
1902
+ if (options.search) {
1903
+ conditions.push({
1904
+ or: [
1905
+ { email: { contains: options.search } },
1906
+ { firstName: { contains: options.search } },
1907
+ { lastName: { contains: options.search } }
1908
+ ]
1909
+ });
1910
+ }
1911
+ if (options.gdprConsent !== void 0) {
1912
+ conditions.push({ gdprConsent: { eq: options.gdprConsent } });
1913
+ }
1914
+ if (options.marketingOptIn !== void 0) {
1915
+ conditions.push({ marketingOptIn: { eq: options.marketingOptIn } });
1916
+ }
1917
+ if (options.tags && options.tags.length > 0) {
1918
+ const tagConditions = options.tags.map((tag) => ({
1919
+ tags: { contains: tag }
1920
+ }));
1921
+ conditions.push({ or: tagConditions });
1922
+ }
1923
+ if (options.filter) {
1924
+ conditions.push(options.filter);
1925
+ }
1926
+ if (conditions.length === 0) {
1927
+ return void 0;
1928
+ }
1929
+ if (conditions.length === 1) {
1930
+ return conditions[0];
1931
+ }
1932
+ return { and: conditions };
1933
+ }
1934
+ var useContactsInternal = createDataHook({
1935
+ model: "Contact",
1936
+ dataPropertyName: "contacts",
1937
+ buildFilter: buildFilter6,
1938
+ computedProperties: {
1939
+ consentedContacts: (contacts) => contacts.filter((c) => c.gdprConsent === true),
1940
+ marketingContacts: (contacts) => contacts.filter((c) => c.marketingOptIn === true)
1941
+ }
1942
+ });
1943
+ function useContacts(options = {}) {
1944
+ const result = useContactsInternal(options);
1945
+ return {
1946
+ contacts: result.contacts,
1947
+ consentedContacts: result.consentedContacts,
1948
+ marketingContacts: result.marketingContacts,
1949
+ loading: result.loading,
1950
+ error: result.error,
1951
+ refetch: result.refetch
1952
+ };
1953
+ }
1954
+
1534
1955
  // ../../node_modules/.pnpm/nanostores@1.1.0/node_modules/nanostores/clean-stores/index.js
1535
1956
  var clean = /* @__PURE__ */ Symbol("clean");
1536
1957
 
@@ -1634,12 +2055,15 @@ function createSingleStore(shared, name, defaultValue) {
1634
2055
  return shared(name, atom(defaultValue));
1635
2056
  }
1636
2057
  export {
2058
+ ContactValidationError,
1637
2059
  DEFAULT_SOFT_DELETE_RETENTION_DAYS,
1638
2060
  ReservationValidationError,
1639
2061
  SYSTEM_SETTINGS_KEY,
1640
2062
  checkRestoreEligibility,
1641
2063
  createAccount,
1642
2064
  createBrand,
2065
+ createContact,
2066
+ createContactSchema,
1643
2067
  createDataHook,
1644
2068
  createProductInstance,
1645
2069
  createReservation2 as createReservation,
@@ -1649,6 +2073,7 @@ export {
1649
2073
  createUser,
1650
2074
  deleteAccount,
1651
2075
  deleteBrand,
2076
+ deleteContact,
1652
2077
  deleteProductInstance,
1653
2078
  deleteReservation2 as deleteReservation,
1654
2079
  deleteUser,
@@ -1660,6 +2085,9 @@ export {
1660
2085
  getAccountWithBrands,
1661
2086
  getBrand,
1662
2087
  getBrandWithProducts,
2088
+ getContact,
2089
+ getContactByEmail,
2090
+ getContactByPhone,
1663
2091
  getErrorMessage,
1664
2092
  getProduct,
1665
2093
  getProductInstance,
@@ -1679,6 +2107,8 @@ export {
1679
2107
  listActiveUsers,
1680
2108
  listBrands,
1681
2109
  listBrandsByAccount,
2110
+ listContacts,
2111
+ listContactsByBrand,
1682
2112
  listEnabledProductInstancesByBrand,
1683
2113
  listProductInstancesByAccount,
1684
2114
  listProductInstancesByBrand,
@@ -1689,21 +2119,28 @@ export {
1689
2119
  listReservationsByDateRange,
1690
2120
  listUsers,
1691
2121
  listUsersByAccount,
2122
+ mergeContacts,
2123
+ mergeContactsSchema,
1692
2124
  mutate,
1693
2125
  query,
1694
2126
  resetClientInstance,
1695
2127
  resetSharedClient,
1696
2128
  restoreAccount,
1697
2129
  restoreBrand,
2130
+ restoreContact,
1698
2131
  restoreReservation2 as restoreReservation,
1699
2132
  restoreUser,
2133
+ searchContacts,
1700
2134
  softDeleteAccount,
1701
2135
  softDeleteBrand,
2136
+ softDeleteContact,
1702
2137
  softDeleteReservation2 as softDeleteReservation,
1703
2138
  softDeleteUser,
1704
2139
  toggleProductInstanceEnabled,
1705
2140
  updateAccount,
1706
2141
  updateBrand,
2142
+ updateContact,
2143
+ updateContactSchema,
1707
2144
  updateProductInstance,
1708
2145
  updateReservation2 as updateReservation,
1709
2146
  updateReservationStatus2 as updateReservationStatus,
@@ -1711,6 +2148,7 @@ export {
1711
2148
  updateUser,
1712
2149
  useAccounts,
1713
2150
  useBrands,
2151
+ useContacts,
1714
2152
  useProductInstances,
1715
2153
  useProducts,
1716
2154
  useReservations,