@htlkg/data 0.0.19 → 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.
Files changed (39) hide show
  1. package/dist/client/index.d.ts +257 -1
  2. package/dist/client/index.js +59 -1
  3. package/dist/client/index.js.map +1 -1
  4. package/dist/common-DSxswsZ3.d.ts +40 -0
  5. package/dist/hooks/index.d.ts +162 -10
  6. package/dist/hooks/index.js +191 -33
  7. package/dist/hooks/index.js.map +1 -1
  8. package/dist/index.d.ts +9 -5
  9. package/dist/index.js +789 -13
  10. package/dist/index.js.map +1 -1
  11. package/dist/mutations/index.d.ts +342 -4
  12. package/dist/mutations/index.js +486 -0
  13. package/dist/mutations/index.js.map +1 -1
  14. package/dist/{productInstances-BA3cNsYc.d.ts → productInstances-BpQv1oLS.d.ts} +2 -40
  15. package/dist/queries/index.d.ts +113 -2
  16. package/dist/queries/index.js +192 -1
  17. package/dist/queries/index.js.map +1 -1
  18. package/dist/reservations-C0FNm__0.d.ts +154 -0
  19. package/dist/reservations-CdDfkcZ_.d.ts +172 -0
  20. package/package.json +14 -13
  21. package/src/client/index.ts +18 -0
  22. package/src/client/reservations.ts +336 -0
  23. package/src/hooks/createDataHook.test.ts +534 -0
  24. package/src/hooks/createDataHook.ts +20 -13
  25. package/src/hooks/index.ts +2 -0
  26. package/src/hooks/useContacts.test.ts +159 -0
  27. package/src/hooks/useContacts.ts +176 -0
  28. package/src/hooks/useReservations.ts +145 -0
  29. package/src/mutations/contacts.test.ts +604 -0
  30. package/src/mutations/contacts.ts +554 -0
  31. package/src/mutations/index.ts +32 -0
  32. package/src/mutations/productInstances/productInstances.test.ts +3 -3
  33. package/src/mutations/reservations.test.ts +459 -0
  34. package/src/mutations/reservations.ts +452 -0
  35. package/src/queries/contacts.test.ts +505 -0
  36. package/src/queries/contacts.ts +237 -0
  37. package/src/queries/index.ts +21 -0
  38. package/src/queries/reservations.test.ts +374 -0
  39. package/src/queries/reservations.ts +247 -0
@@ -509,26 +509,512 @@ async function initializeSystemSettings(client, initializedBy) {
509
509
  throw error;
510
510
  }
511
511
  }
512
+
513
+ // src/mutations/reservations.ts
514
+ var STATUS_TRANSITIONS = {
515
+ confirmed: ["checked_in", "cancelled", "no_show"],
516
+ checked_in: ["checked_out", "cancelled"],
517
+ checked_out: [],
518
+ // Terminal state - no transitions allowed
519
+ cancelled: [],
520
+ // Terminal state - no transitions allowed
521
+ no_show: []
522
+ // Terminal state - no transitions allowed
523
+ };
524
+ var ReservationValidationError = class extends Error {
525
+ constructor(message) {
526
+ super(message);
527
+ this.name = "ReservationValidationError";
528
+ }
529
+ };
530
+ function validateDates(checkIn, checkOut) {
531
+ const checkInDate = new Date(checkIn);
532
+ const checkOutDate = new Date(checkOut);
533
+ if (isNaN(checkInDate.getTime())) {
534
+ throw new ReservationValidationError("Invalid check-in date");
535
+ }
536
+ if (isNaN(checkOutDate.getTime())) {
537
+ throw new ReservationValidationError("Invalid check-out date");
538
+ }
539
+ if (checkOutDate <= checkInDate) {
540
+ throw new ReservationValidationError(
541
+ "Check-out date must be after check-in date"
542
+ );
543
+ }
544
+ const minStayHours = 4;
545
+ const stayDuration = checkOutDate.getTime() - checkInDate.getTime();
546
+ const hoursDiff = stayDuration / (1e3 * 60 * 60);
547
+ if (hoursDiff < minStayHours) {
548
+ throw new ReservationValidationError(
549
+ `Minimum stay is ${minStayHours} hours`
550
+ );
551
+ }
552
+ }
553
+ function validateStatusTransition(currentStatus, newStatus) {
554
+ const allowedTransitions = STATUS_TRANSITIONS[currentStatus];
555
+ if (!allowedTransitions.includes(newStatus)) {
556
+ throw new ReservationValidationError(
557
+ `Invalid status transition from '${currentStatus}' to '${newStatus}'. Allowed transitions: ${allowedTransitions.length > 0 ? allowedTransitions.join(", ") : "none (terminal state)"}`
558
+ );
559
+ }
560
+ }
561
+ async function createReservation(client, input) {
562
+ try {
563
+ validateDates(input.checkIn, input.checkOut);
564
+ if (!input.nights) {
565
+ const checkInDate = new Date(input.checkIn);
566
+ const checkOutDate = new Date(input.checkOut);
567
+ const diffTime = checkOutDate.getTime() - checkInDate.getTime();
568
+ const diffDays = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
569
+ input.nights = diffDays;
570
+ }
571
+ const { data, errors } = await client.models.Reservation.create(input);
572
+ if (errors) {
573
+ console.error("[createReservation] GraphQL errors:", errors);
574
+ return null;
575
+ }
576
+ return data;
577
+ } catch (error) {
578
+ if (error instanceof ReservationValidationError) {
579
+ console.error("[createReservation] Validation error:", error.message);
580
+ throw error;
581
+ }
582
+ console.error("[createReservation] Error creating reservation:", error);
583
+ throw error;
584
+ }
585
+ }
586
+ async function updateReservation(client, input) {
587
+ try {
588
+ if (input.checkIn && input.checkOut) {
589
+ validateDates(input.checkIn, input.checkOut);
590
+ const checkInDate = new Date(input.checkIn);
591
+ const checkOutDate = new Date(input.checkOut);
592
+ const diffTime = checkOutDate.getTime() - checkInDate.getTime();
593
+ const diffDays = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
594
+ input.nights = diffDays;
595
+ }
596
+ if (input.status) {
597
+ const { data: currentReservation, errors: getErrors } = await client.models.Reservation.get({ id: input.id });
598
+ if (getErrors || !currentReservation) {
599
+ console.error("[updateReservation] Error fetching current reservation:", getErrors);
600
+ return null;
601
+ }
602
+ const currentStatus = currentReservation.status;
603
+ validateStatusTransition(currentStatus, input.status);
604
+ }
605
+ const { data, errors } = await client.models.Reservation.update(input);
606
+ if (errors) {
607
+ console.error("[updateReservation] GraphQL errors:", errors);
608
+ return null;
609
+ }
610
+ return data;
611
+ } catch (error) {
612
+ if (error instanceof ReservationValidationError) {
613
+ console.error("[updateReservation] Validation error:", error.message);
614
+ throw error;
615
+ }
616
+ console.error("[updateReservation] Error updating reservation:", error);
617
+ throw error;
618
+ }
619
+ }
620
+ async function softDeleteReservation(client, id, deletedBy) {
621
+ try {
622
+ const { errors } = await client.models.Reservation.update({
623
+ id,
624
+ deletedAt: (/* @__PURE__ */ new Date()).toISOString(),
625
+ deletedBy
626
+ });
627
+ if (errors) {
628
+ console.error("[softDeleteReservation] GraphQL errors:", errors);
629
+ return false;
630
+ }
631
+ return true;
632
+ } catch (error) {
633
+ console.error("[softDeleteReservation] Error soft-deleting reservation:", error);
634
+ throw error;
635
+ }
636
+ }
637
+ async function restoreReservation(client, id, retentionDays = DEFAULT_SOFT_DELETE_RETENTION_DAYS) {
638
+ try {
639
+ const { data: reservation, errors: getErrors } = await client.models.Reservation.get({ id });
640
+ if (getErrors || !reservation) {
641
+ console.error("[restoreReservation] Error fetching reservation:", getErrors);
642
+ return { success: false, error: "Reservation not found" };
643
+ }
644
+ const eligibility = checkRestoreEligibility(reservation.deletedAt, retentionDays);
645
+ if (!eligibility.canRestore) {
646
+ const errorMsg = `Cannot restore reservation. Retention period of ${retentionDays} days has expired. Item was deleted ${eligibility.daysExpired} days ago.`;
647
+ console.error("[restoreReservation]", errorMsg);
648
+ return { success: false, error: errorMsg };
649
+ }
650
+ const { errors } = await client.models.Reservation.update({
651
+ id,
652
+ deletedAt: null,
653
+ deletedBy: null
654
+ });
655
+ if (errors) {
656
+ console.error("[restoreReservation] GraphQL errors:", errors);
657
+ return { success: false, error: "Failed to restore reservation" };
658
+ }
659
+ return { success: true };
660
+ } catch (error) {
661
+ console.error("[restoreReservation] Error restoring reservation:", error);
662
+ throw error;
663
+ }
664
+ }
665
+ async function deleteReservation(client, id) {
666
+ try {
667
+ const { errors } = await client.models.Reservation.delete({ id });
668
+ if (errors) {
669
+ console.error("[deleteReservation] GraphQL errors:", errors);
670
+ return false;
671
+ }
672
+ return true;
673
+ } catch (error) {
674
+ console.error("[deleteReservation] Error deleting reservation:", error);
675
+ throw error;
676
+ }
677
+ }
678
+ async function updateReservationStatus(client, id, newStatus) {
679
+ try {
680
+ const { data: currentReservation, errors: getErrors } = await client.models.Reservation.get({ id });
681
+ if (getErrors || !currentReservation) {
682
+ console.error("[updateReservationStatus] Error fetching reservation:", getErrors);
683
+ return null;
684
+ }
685
+ const currentStatus = currentReservation.status;
686
+ validateStatusTransition(currentStatus, newStatus);
687
+ const { data, errors } = await client.models.Reservation.update({
688
+ id,
689
+ status: newStatus
690
+ });
691
+ if (errors) {
692
+ console.error("[updateReservationStatus] GraphQL errors:", errors);
693
+ return null;
694
+ }
695
+ return data;
696
+ } catch (error) {
697
+ if (error instanceof ReservationValidationError) {
698
+ console.error("[updateReservationStatus] Validation error:", error.message);
699
+ throw error;
700
+ }
701
+ console.error("[updateReservationStatus] Error updating status:", error);
702
+ throw error;
703
+ }
704
+ }
705
+
706
+ // src/mutations/contacts.ts
707
+ import { z } from "zod";
708
+
709
+ // src/queries/contacts.ts
710
+ async function getContact(client, id) {
711
+ try {
712
+ const { data, errors } = await client.models.Contact.get({ id });
713
+ if (errors) {
714
+ console.error("[getContact] GraphQL errors:", errors);
715
+ return null;
716
+ }
717
+ return data;
718
+ } catch (error) {
719
+ console.error("[getContact] Error fetching contact:", error);
720
+ throw error;
721
+ }
722
+ }
723
+
724
+ // src/mutations/contacts.ts
725
+ var createContactSchema = z.object({
726
+ brandId: z.string().min(1, "Brand ID is required"),
727
+ email: z.string().email("Invalid email address"),
728
+ phone: z.string().optional(),
729
+ firstName: z.string().min(1, "First name is required"),
730
+ lastName: z.string().min(1, "Last name is required"),
731
+ locale: z.string().optional(),
732
+ gdprConsent: z.boolean(),
733
+ gdprConsentDate: z.string().optional(),
734
+ marketingOptIn: z.boolean().optional(),
735
+ preferences: z.record(z.any()).optional(),
736
+ tags: z.array(z.string()).optional(),
737
+ totalVisits: z.number().int().min(0).optional(),
738
+ lastVisitDate: z.string().optional(),
739
+ firstVisitDate: z.string().optional(),
740
+ legacyId: z.string().optional(),
741
+ // Audit fields
742
+ createdAt: z.string().optional(),
743
+ createdBy: z.string().optional(),
744
+ updatedAt: z.string().optional(),
745
+ updatedBy: z.string().optional()
746
+ });
747
+ var updateContactSchema = z.object({
748
+ id: z.string().min(1, "Contact ID is required"),
749
+ brandId: z.string().min(1).optional(),
750
+ email: z.string().email("Invalid email address").optional(),
751
+ phone: z.string().optional(),
752
+ firstName: z.string().min(1).optional(),
753
+ lastName: z.string().min(1).optional(),
754
+ locale: z.string().optional(),
755
+ gdprConsent: z.boolean().optional(),
756
+ gdprConsentDate: z.string().optional(),
757
+ marketingOptIn: z.boolean().optional(),
758
+ preferences: z.record(z.any()).optional(),
759
+ tags: z.array(z.string()).optional(),
760
+ totalVisits: z.number().int().min(0).optional(),
761
+ lastVisitDate: z.string().optional(),
762
+ firstVisitDate: z.string().optional(),
763
+ legacyId: z.string().optional(),
764
+ // Audit fields
765
+ updatedAt: z.string().optional(),
766
+ updatedBy: z.string().optional(),
767
+ deletedAt: z.string().nullable().optional(),
768
+ deletedBy: z.string().nullable().optional()
769
+ });
770
+ var mergeContactsSchema = z.object({
771
+ primaryId: z.string().min(1, "Primary contact ID is required"),
772
+ duplicateIds: z.array(z.string().min(1)).min(1, "At least one duplicate ID is required")
773
+ });
774
+ var ContactValidationError = class extends Error {
775
+ issues;
776
+ constructor(message, issues = []) {
777
+ super(message);
778
+ this.name = "ContactValidationError";
779
+ this.issues = issues;
780
+ }
781
+ };
782
+ async function createContact(client, input) {
783
+ try {
784
+ const validationResult = createContactSchema.safeParse(input);
785
+ if (!validationResult.success) {
786
+ const errorMessage = validationResult.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join(", ");
787
+ throw new ContactValidationError(
788
+ `Validation failed: ${errorMessage}`,
789
+ validationResult.error.issues
790
+ );
791
+ }
792
+ const { data, errors } = await client.models.Contact.create(input);
793
+ if (errors) {
794
+ console.error("[createContact] GraphQL errors:", errors);
795
+ return null;
796
+ }
797
+ return data;
798
+ } catch (error) {
799
+ if (error instanceof ContactValidationError) {
800
+ console.error("[createContact] Validation error:", error.message);
801
+ throw error;
802
+ }
803
+ console.error("[createContact] Error creating contact:", error);
804
+ throw error;
805
+ }
806
+ }
807
+ async function updateContact(client, input) {
808
+ try {
809
+ const validationResult = updateContactSchema.safeParse(input);
810
+ if (!validationResult.success) {
811
+ const errorMessage = validationResult.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join(", ");
812
+ throw new ContactValidationError(
813
+ `Validation failed: ${errorMessage}`,
814
+ validationResult.error.issues
815
+ );
816
+ }
817
+ const { data, errors } = await client.models.Contact.update(input);
818
+ if (errors) {
819
+ console.error("[updateContact] GraphQL errors:", errors);
820
+ return null;
821
+ }
822
+ return data;
823
+ } catch (error) {
824
+ if (error instanceof ContactValidationError) {
825
+ console.error("[updateContact] Validation error:", error.message);
826
+ throw error;
827
+ }
828
+ console.error("[updateContact] Error updating contact:", error);
829
+ throw error;
830
+ }
831
+ }
832
+ async function softDeleteContact(client, id, deletedBy) {
833
+ try {
834
+ const { errors } = await client.models.Contact.update({
835
+ id,
836
+ deletedAt: (/* @__PURE__ */ new Date()).toISOString(),
837
+ deletedBy
838
+ });
839
+ if (errors) {
840
+ console.error("[softDeleteContact] GraphQL errors:", errors);
841
+ return false;
842
+ }
843
+ return true;
844
+ } catch (error) {
845
+ console.error("[softDeleteContact] Error soft-deleting contact:", error);
846
+ throw error;
847
+ }
848
+ }
849
+ async function restoreContact(client, id, retentionDays = DEFAULT_SOFT_DELETE_RETENTION_DAYS) {
850
+ try {
851
+ const contact = await getContact(client, id);
852
+ if (!contact) {
853
+ console.error("[restoreContact] Contact not found");
854
+ return { success: false, error: "Contact not found" };
855
+ }
856
+ const eligibility = checkRestoreEligibility(
857
+ contact.deletedAt,
858
+ retentionDays
859
+ );
860
+ if (!eligibility.canRestore) {
861
+ const errorMsg = `Cannot restore contact. Retention period of ${retentionDays} days has expired. Item was deleted ${eligibility.daysExpired} days ago.`;
862
+ console.error("[restoreContact]", errorMsg);
863
+ return { success: false, error: errorMsg };
864
+ }
865
+ const { errors } = await client.models.Contact.update({
866
+ id,
867
+ deletedAt: null,
868
+ deletedBy: null
869
+ });
870
+ if (errors) {
871
+ console.error("[restoreContact] GraphQL errors:", errors);
872
+ return { success: false, error: "Failed to restore contact" };
873
+ }
874
+ return { success: true };
875
+ } catch (error) {
876
+ console.error("[restoreContact] Error restoring contact:", error);
877
+ throw error;
878
+ }
879
+ }
880
+ async function deleteContact(client, id) {
881
+ try {
882
+ const { errors } = await client.models.Contact.delete({ id });
883
+ if (errors) {
884
+ console.error("[deleteContact] GraphQL errors:", errors);
885
+ return false;
886
+ }
887
+ return true;
888
+ } catch (error) {
889
+ console.error("[deleteContact] Error deleting contact:", error);
890
+ throw error;
891
+ }
892
+ }
893
+ async function mergeContacts(client, input, mergedBy) {
894
+ try {
895
+ const validationResult = mergeContactsSchema.safeParse(input);
896
+ if (!validationResult.success) {
897
+ const errorMessage = validationResult.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join(", ");
898
+ throw new ContactValidationError(
899
+ `Validation failed: ${errorMessage}`,
900
+ validationResult.error.issues
901
+ );
902
+ }
903
+ const { primaryId, duplicateIds } = input;
904
+ const primaryContact = await getContact(client, primaryId);
905
+ if (!primaryContact) {
906
+ return {
907
+ success: false,
908
+ error: `Primary contact not found: ${primaryId}`
909
+ };
910
+ }
911
+ const duplicateContacts = [];
912
+ for (const duplicateId of duplicateIds) {
913
+ const duplicate = await getContact(client, duplicateId);
914
+ if (!duplicate) {
915
+ return {
916
+ success: false,
917
+ error: `Duplicate contact not found: ${duplicateId}`
918
+ };
919
+ }
920
+ duplicateContacts.push(duplicate);
921
+ }
922
+ let totalVisits = primaryContact.totalVisits || 0;
923
+ let firstVisitDate = primaryContact.firstVisitDate;
924
+ let lastVisitDate = primaryContact.lastVisitDate;
925
+ const allTags = new Set(primaryContact.tags || []);
926
+ for (const duplicate of duplicateContacts) {
927
+ totalVisits += duplicate.totalVisits || 0;
928
+ if (duplicate.firstVisitDate) {
929
+ if (!firstVisitDate || duplicate.firstVisitDate < firstVisitDate) {
930
+ firstVisitDate = duplicate.firstVisitDate;
931
+ }
932
+ }
933
+ if (duplicate.lastVisitDate) {
934
+ if (!lastVisitDate || duplicate.lastVisitDate > lastVisitDate) {
935
+ lastVisitDate = duplicate.lastVisitDate;
936
+ }
937
+ }
938
+ if (duplicate.tags) {
939
+ duplicate.tags.forEach((tag) => allTags.add(tag));
940
+ }
941
+ }
942
+ const updateInput = {
943
+ id: primaryId,
944
+ totalVisits,
945
+ firstVisitDate,
946
+ lastVisitDate,
947
+ tags: Array.from(allTags),
948
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
949
+ updatedBy: mergedBy
950
+ };
951
+ const updatedPrimary = await updateContact(client, updateInput);
952
+ if (!updatedPrimary) {
953
+ return {
954
+ success: false,
955
+ error: "Failed to update primary contact with merged data"
956
+ };
957
+ }
958
+ const deletedIds = [];
959
+ for (const duplicateId of duplicateIds) {
960
+ const deleted = await softDeleteContact(client, duplicateId, mergedBy);
961
+ if (deleted) {
962
+ deletedIds.push(duplicateId);
963
+ } else {
964
+ console.error(`[mergeContacts] Failed to soft-delete duplicate: ${duplicateId}`);
965
+ }
966
+ }
967
+ return {
968
+ success: true,
969
+ mergedContact: updatedPrimary,
970
+ deletedIds
971
+ };
972
+ } catch (error) {
973
+ if (error instanceof ContactValidationError) {
974
+ console.error("[mergeContacts] Validation error:", error.message);
975
+ throw error;
976
+ }
977
+ console.error("[mergeContacts] Error merging contacts:", error);
978
+ throw error;
979
+ }
980
+ }
512
981
  export {
982
+ ContactValidationError,
983
+ ReservationValidationError,
513
984
  createAccount,
514
985
  createBrand,
986
+ createContact,
987
+ createContactSchema,
515
988
  createProductInstance,
989
+ createReservation,
516
990
  createUser,
517
991
  deleteAccount,
518
992
  deleteBrand,
993
+ deleteContact,
519
994
  deleteProductInstance,
995
+ deleteReservation,
520
996
  deleteUser,
521
997
  initializeSystemSettings,
998
+ mergeContacts,
999
+ mergeContactsSchema,
522
1000
  restoreAccount,
523
1001
  restoreBrand,
1002
+ restoreContact,
1003
+ restoreReservation,
524
1004
  restoreUser,
525
1005
  softDeleteAccount,
526
1006
  softDeleteBrand,
1007
+ softDeleteContact,
1008
+ softDeleteReservation,
527
1009
  softDeleteUser,
528
1010
  toggleProductInstanceEnabled,
529
1011
  updateAccount,
530
1012
  updateBrand,
1013
+ updateContact,
1014
+ updateContactSchema,
531
1015
  updateProductInstance,
1016
+ updateReservation,
1017
+ updateReservationStatus,
532
1018
  updateSystemSettings,
533
1019
  updateUser
534
1020
  };