@spotsdev/sdk 1.2.0 → 1.3.0

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.
@@ -11,3 +11,4 @@ export * from './clubs';
11
11
  export * from './notifications';
12
12
  export * from './products';
13
13
  export * from './orders';
14
+ export * from './redemptions';
@@ -35,4 +35,6 @@ __exportStar(require("./notifications"), exports);
35
35
  __exportStar(require("./products"), exports);
36
36
  // Orders (marketplace)
37
37
  __exportStar(require("./orders"), exports);
38
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpL211dGF0aW9ucy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7R0FJRzs7Ozs7Ozs7Ozs7Ozs7OztBQUVILFFBQVE7QUFDUiwwQ0FBdUI7QUFFdkIsUUFBUTtBQUNSLDBDQUF1QjtBQUV2QixRQUFRO0FBQ1IsMENBQXVCO0FBRXZCLGdCQUFnQjtBQUNoQixrREFBK0I7QUFFL0IsUUFBUTtBQUNSLDBDQUF1QjtBQUV2QixnQkFBZ0I7QUFDaEIsa0RBQStCO0FBRS9CLHlCQUF5QjtBQUN6Qiw2Q0FBMEI7QUFFMUIsdUJBQXVCO0FBQ3ZCLDJDQUF3QiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU3BvdHMgU0RLIE11dGF0aW9uIEhvb2tzIEluZGV4XG4gKlxuICogUmUtZXhwb3J0cyBhbGwgbXV0YXRpb24gaG9va3MuXG4gKi9cblxuLy8gVXNlcnNcbmV4cG9ydCAqIGZyb20gJy4vdXNlcnMnXG5cbi8vIFBvc3RzXG5leHBvcnQgKiBmcm9tICcuL3Bvc3RzJ1xuXG4vLyBTcG90c1xuZXhwb3J0ICogZnJvbSAnLi9zcG90cydcblxuLy8gQ29udmVyc2F0aW9uc1xuZXhwb3J0ICogZnJvbSAnLi9jb252ZXJzYXRpb25zJ1xuXG4vLyBDbHVic1xuZXhwb3J0ICogZnJvbSAnLi9jbHVicydcblxuLy8gTm90aWZpY2F0aW9uc1xuZXhwb3J0ICogZnJvbSAnLi9ub3RpZmljYXRpb25zJ1xuXG4vLyBQcm9kdWN0cyAobWFya2V0cGxhY2UpXG5leHBvcnQgKiBmcm9tICcuL3Byb2R1Y3RzJ1xuXG4vLyBPcmRlcnMgKG1hcmtldHBsYWNlKVxuZXhwb3J0ICogZnJvbSAnLi9vcmRlcnMnXG4iXX0=
38
+ // Redemptions (wallet)
39
+ __exportStar(require("./redemptions"), exports);
40
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpL211dGF0aW9ucy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7R0FJRzs7Ozs7Ozs7Ozs7Ozs7OztBQUVILFFBQVE7QUFDUiwwQ0FBdUI7QUFFdkIsUUFBUTtBQUNSLDBDQUF1QjtBQUV2QixRQUFRO0FBQ1IsMENBQXVCO0FBRXZCLGdCQUFnQjtBQUNoQixrREFBK0I7QUFFL0IsUUFBUTtBQUNSLDBDQUF1QjtBQUV2QixnQkFBZ0I7QUFDaEIsa0RBQStCO0FBRS9CLHlCQUF5QjtBQUN6Qiw2Q0FBMEI7QUFFMUIsdUJBQXVCO0FBQ3ZCLDJDQUF3QjtBQUV4Qix1QkFBdUI7QUFDdkIsZ0RBQTZCIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBTcG90cyBTREsgTXV0YXRpb24gSG9va3MgSW5kZXhcbiAqXG4gKiBSZS1leHBvcnRzIGFsbCBtdXRhdGlvbiBob29rcy5cbiAqL1xuXG4vLyBVc2Vyc1xuZXhwb3J0ICogZnJvbSAnLi91c2VycydcblxuLy8gUG9zdHNcbmV4cG9ydCAqIGZyb20gJy4vcG9zdHMnXG5cbi8vIFNwb3RzXG5leHBvcnQgKiBmcm9tICcuL3Nwb3RzJ1xuXG4vLyBDb252ZXJzYXRpb25zXG5leHBvcnQgKiBmcm9tICcuL2NvbnZlcnNhdGlvbnMnXG5cbi8vIENsdWJzXG5leHBvcnQgKiBmcm9tICcuL2NsdWJzJ1xuXG4vLyBOb3RpZmljYXRpb25zXG5leHBvcnQgKiBmcm9tICcuL25vdGlmaWNhdGlvbnMnXG5cbi8vIFByb2R1Y3RzIChtYXJrZXRwbGFjZSlcbmV4cG9ydCAqIGZyb20gJy4vcHJvZHVjdHMnXG5cbi8vIE9yZGVycyAobWFya2V0cGxhY2UpXG5leHBvcnQgKiBmcm9tICcuL29yZGVycydcblxuLy8gUmVkZW1wdGlvbnMgKHdhbGxldClcbmV4cG9ydCAqIGZyb20gJy4vcmVkZW1wdGlvbnMnXG4iXX0=
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Redemption Mutation Hooks
3
+ *
4
+ * TanStack Query mutations for redemption operations.
5
+ */
6
+ import { type UseMutationResult } from '@tanstack/react-query';
7
+ import { type WalletRedemption } from '../queries/wallet';
8
+ export interface RedeemRequest {
9
+ qrCode: string;
10
+ spotId?: string;
11
+ deviceInfo?: string;
12
+ latitude?: number;
13
+ longitude?: number;
14
+ notes?: string;
15
+ }
16
+ export interface VoidRedemptionRequest {
17
+ reason: string;
18
+ }
19
+ /**
20
+ * Redeem a QR code (spot owner/staff action)
21
+ *
22
+ * @endpoint POST /redemptions/redeem
23
+ */
24
+ export declare function useRedeem(): UseMutationResult<WalletRedemption, Error, RedeemRequest>;
25
+ /**
26
+ * Void a redemption (spot owner action)
27
+ *
28
+ * @endpoint PUT /redemptions/:id/void
29
+ */
30
+ export declare function useVoidRedemption(): UseMutationResult<WalletRedemption, Error, {
31
+ redemptionId: string;
32
+ reason: string;
33
+ }>;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ /**
3
+ * Redemption Mutation Hooks
4
+ *
5
+ * TanStack Query mutations for redemption operations.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.useRedeem = useRedeem;
9
+ exports.useVoidRedemption = useVoidRedemption;
10
+ const react_query_1 = require("@tanstack/react-query");
11
+ const client_1 = require("../client");
12
+ const wallet_1 = require("../queries/wallet");
13
+ // ============================================================================
14
+ // MUTATION HOOKS
15
+ // ============================================================================
16
+ /**
17
+ * Redeem a QR code (spot owner/staff action)
18
+ *
19
+ * @endpoint POST /redemptions/redeem
20
+ */
21
+ function useRedeem() {
22
+ const queryClient = (0, react_query_1.useQueryClient)();
23
+ return (0, react_query_1.useMutation)({
24
+ mutationFn: async (request) => {
25
+ const client = (0, client_1.getApiClient)();
26
+ const response = await client.post('/redemptions/redeem', request);
27
+ return response.data.data;
28
+ },
29
+ onSuccess: (_data, variables) => {
30
+ // Invalidate redemption lookup for this QR code
31
+ queryClient.invalidateQueries({
32
+ queryKey: wallet_1.walletKeys.lookup(variables.qrCode),
33
+ });
34
+ // Invalidate spot redemptions if spotId provided
35
+ if (variables.spotId) {
36
+ queryClient.invalidateQueries({
37
+ queryKey: wallet_1.walletKeys.spotRedemptions(variables.spotId),
38
+ });
39
+ }
40
+ },
41
+ });
42
+ }
43
+ /**
44
+ * Void a redemption (spot owner action)
45
+ *
46
+ * @endpoint PUT /redemptions/:id/void
47
+ */
48
+ function useVoidRedemption() {
49
+ const queryClient = (0, react_query_1.useQueryClient)();
50
+ return (0, react_query_1.useMutation)({
51
+ mutationFn: async ({ redemptionId, reason, }) => {
52
+ const client = (0, client_1.getApiClient)();
53
+ const response = await client.put(`/redemptions/${redemptionId}/void`, { reason });
54
+ return response.data.data;
55
+ },
56
+ onSuccess: () => {
57
+ // Invalidate wallet queries
58
+ queryClient.invalidateQueries({ queryKey: wallet_1.walletKeys.all });
59
+ queryClient.invalidateQueries({ queryKey: wallet_1.walletKeys.redemptions() });
60
+ },
61
+ });
62
+ }
63
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkZW1wdGlvbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpL211dGF0aW9ucy9yZWRlbXB0aW9ucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7R0FJRzs7QUFnQ0gsOEJBc0JDO0FBT0QsOENBeUJDO0FBcEZELHVEQUF5RjtBQUN6RixzQ0FBc0M7QUFDdEMsOENBQW1FO0FBbUJuRSwrRUFBK0U7QUFDL0UsaUJBQWlCO0FBQ2pCLCtFQUErRTtBQUUvRTs7OztHQUlHO0FBQ0gsU0FBZ0IsU0FBUztJQUN2QixNQUFNLFdBQVcsR0FBRyxJQUFBLDRCQUFjLEdBQUUsQ0FBQTtJQUVwQyxPQUFPLElBQUEseUJBQVcsRUFBQztRQUNqQixVQUFVLEVBQUUsS0FBSyxFQUFFLE9BQXNCLEVBQTZCLEVBQUU7WUFDdEUsTUFBTSxNQUFNLEdBQUcsSUFBQSxxQkFBWSxHQUFFLENBQUE7WUFDN0IsTUFBTSxRQUFRLEdBQUcsTUFBTSxNQUFNLENBQUMsSUFBSSxDQUFDLHFCQUFxQixFQUFFLE9BQU8sQ0FBQyxDQUFBO1lBQ2xFLE9BQU8sUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUE7UUFDM0IsQ0FBQztRQUNELFNBQVMsRUFBRSxDQUFDLEtBQUssRUFBRSxTQUFTLEVBQUUsRUFBRTtZQUM5QixnREFBZ0Q7WUFDaEQsV0FBVyxDQUFDLGlCQUFpQixDQUFDO2dCQUM1QixRQUFRLEVBQUUsbUJBQVUsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQzthQUM5QyxDQUFDLENBQUE7WUFDRixpREFBaUQ7WUFDakQsSUFBSSxTQUFTLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQ3JCLFdBQVcsQ0FBQyxpQkFBaUIsQ0FBQztvQkFDNUIsUUFBUSxFQUFFLG1CQUFVLENBQUMsZUFBZSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7aUJBQ3ZELENBQUMsQ0FBQTtZQUNKLENBQUM7UUFDSCxDQUFDO0tBQ0YsQ0FBQyxDQUFBO0FBQ0osQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFnQixpQkFBaUI7SUFLL0IsTUFBTSxXQUFXLEdBQUcsSUFBQSw0QkFBYyxHQUFFLENBQUE7SUFFcEMsT0FBTyxJQUFBLHlCQUFXLEVBQUM7UUFDakIsVUFBVSxFQUFFLEtBQUssRUFBRSxFQUNqQixZQUFZLEVBQ1osTUFBTSxHQUlQLEVBQTZCLEVBQUU7WUFDOUIsTUFBTSxNQUFNLEdBQUcsSUFBQSxxQkFBWSxHQUFFLENBQUE7WUFDN0IsTUFBTSxRQUFRLEdBQUcsTUFBTSxNQUFNLENBQUMsR0FBRyxDQUFDLGdCQUFnQixZQUFZLE9BQU8sRUFBRSxFQUFDLE1BQU0sRUFBQyxDQUFDLENBQUE7WUFDaEYsT0FBTyxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQTtRQUMzQixDQUFDO1FBQ0QsU0FBUyxFQUFFLEdBQUcsRUFBRTtZQUNkLDRCQUE0QjtZQUM1QixXQUFXLENBQUMsaUJBQWlCLENBQUMsRUFBQyxRQUFRLEVBQUUsbUJBQVUsQ0FBQyxHQUFHLEVBQUMsQ0FBQyxDQUFBO1lBQ3pELFdBQVcsQ0FBQyxpQkFBaUIsQ0FBQyxFQUFDLFFBQVEsRUFBRSxtQkFBVSxDQUFDLFdBQVcsRUFBRSxFQUFDLENBQUMsQ0FBQTtRQUNyRSxDQUFDO0tBQ0YsQ0FBQyxDQUFBO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUmVkZW1wdGlvbiBNdXRhdGlvbiBIb29rc1xuICpcbiAqIFRhblN0YWNrIFF1ZXJ5IG11dGF0aW9ucyBmb3IgcmVkZW1wdGlvbiBvcGVyYXRpb25zLlxuICovXG5cbmltcG9ydCB7dXNlTXV0YXRpb24sIHVzZVF1ZXJ5Q2xpZW50LCB0eXBlIFVzZU11dGF0aW9uUmVzdWx0fSBmcm9tICdAdGFuc3RhY2svcmVhY3QtcXVlcnknXG5pbXBvcnQge2dldEFwaUNsaWVudH0gZnJvbSAnLi4vY2xpZW50J1xuaW1wb3J0IHt3YWxsZXRLZXlzLCB0eXBlIFdhbGxldFJlZGVtcHRpb259IGZyb20gJy4uL3F1ZXJpZXMvd2FsbGV0J1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBUWVBFU1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgaW50ZXJmYWNlIFJlZGVlbVJlcXVlc3Qge1xuICBxckNvZGU6IHN0cmluZ1xuICBzcG90SWQ/OiBzdHJpbmdcbiAgZGV2aWNlSW5mbz86IHN0cmluZ1xuICBsYXRpdHVkZT86IG51bWJlclxuICBsb25naXR1ZGU/OiBudW1iZXJcbiAgbm90ZXM/OiBzdHJpbmdcbn1cblxuZXhwb3J0IGludGVyZmFjZSBWb2lkUmVkZW1wdGlvblJlcXVlc3Qge1xuICByZWFzb246IHN0cmluZ1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBNVVRBVElPTiBIT09LU1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIFJlZGVlbSBhIFFSIGNvZGUgKHNwb3Qgb3duZXIvc3RhZmYgYWN0aW9uKVxuICpcbiAqIEBlbmRwb2ludCBQT1NUIC9yZWRlbXB0aW9ucy9yZWRlZW1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVzZVJlZGVlbSgpOiBVc2VNdXRhdGlvblJlc3VsdDxXYWxsZXRSZWRlbXB0aW9uLCBFcnJvciwgUmVkZWVtUmVxdWVzdD4ge1xuICBjb25zdCBxdWVyeUNsaWVudCA9IHVzZVF1ZXJ5Q2xpZW50KClcblxuICByZXR1cm4gdXNlTXV0YXRpb24oe1xuICAgIG11dGF0aW9uRm46IGFzeW5jIChyZXF1ZXN0OiBSZWRlZW1SZXF1ZXN0KTogUHJvbWlzZTxXYWxsZXRSZWRlbXB0aW9uPiA9PiB7XG4gICAgICBjb25zdCBjbGllbnQgPSBnZXRBcGlDbGllbnQoKVxuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBjbGllbnQucG9zdCgnL3JlZGVtcHRpb25zL3JlZGVlbScsIHJlcXVlc3QpXG4gICAgICByZXR1cm4gcmVzcG9uc2UuZGF0YS5kYXRhXG4gICAgfSxcbiAgICBvblN1Y2Nlc3M6IChfZGF0YSwgdmFyaWFibGVzKSA9PiB7XG4gICAgICAvLyBJbnZhbGlkYXRlIHJlZGVtcHRpb24gbG9va3VwIGZvciB0aGlzIFFSIGNvZGVcbiAgICAgIHF1ZXJ5Q2xpZW50LmludmFsaWRhdGVRdWVyaWVzKHtcbiAgICAgICAgcXVlcnlLZXk6IHdhbGxldEtleXMubG9va3VwKHZhcmlhYmxlcy5xckNvZGUpLFxuICAgICAgfSlcbiAgICAgIC8vIEludmFsaWRhdGUgc3BvdCByZWRlbXB0aW9ucyBpZiBzcG90SWQgcHJvdmlkZWRcbiAgICAgIGlmICh2YXJpYWJsZXMuc3BvdElkKSB7XG4gICAgICAgIHF1ZXJ5Q2xpZW50LmludmFsaWRhdGVRdWVyaWVzKHtcbiAgICAgICAgICBxdWVyeUtleTogd2FsbGV0S2V5cy5zcG90UmVkZW1wdGlvbnModmFyaWFibGVzLnNwb3RJZCksXG4gICAgICAgIH0pXG4gICAgICB9XG4gICAgfSxcbiAgfSlcbn1cblxuLyoqXG4gKiBWb2lkIGEgcmVkZW1wdGlvbiAoc3BvdCBvd25lciBhY3Rpb24pXG4gKlxuICogQGVuZHBvaW50IFBVVCAvcmVkZW1wdGlvbnMvOmlkL3ZvaWRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVzZVZvaWRSZWRlbXB0aW9uKCk6IFVzZU11dGF0aW9uUmVzdWx0PFxuICBXYWxsZXRSZWRlbXB0aW9uLFxuICBFcnJvcixcbiAge3JlZGVtcHRpb25JZDogc3RyaW5nOyByZWFzb246IHN0cmluZ31cbj4ge1xuICBjb25zdCBxdWVyeUNsaWVudCA9IHVzZVF1ZXJ5Q2xpZW50KClcblxuICByZXR1cm4gdXNlTXV0YXRpb24oe1xuICAgIG11dGF0aW9uRm46IGFzeW5jICh7XG4gICAgICByZWRlbXB0aW9uSWQsXG4gICAgICByZWFzb24sXG4gICAgfToge1xuICAgICAgcmVkZW1wdGlvbklkOiBzdHJpbmdcbiAgICAgIHJlYXNvbjogc3RyaW5nXG4gICAgfSk6IFByb21pc2U8V2FsbGV0UmVkZW1wdGlvbj4gPT4ge1xuICAgICAgY29uc3QgY2xpZW50ID0gZ2V0QXBpQ2xpZW50KClcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2xpZW50LnB1dChgL3JlZGVtcHRpb25zLyR7cmVkZW1wdGlvbklkfS92b2lkYCwge3JlYXNvbn0pXG4gICAgICByZXR1cm4gcmVzcG9uc2UuZGF0YS5kYXRhXG4gICAgfSxcbiAgICBvblN1Y2Nlc3M6ICgpID0+IHtcbiAgICAgIC8vIEludmFsaWRhdGUgd2FsbGV0IHF1ZXJpZXNcbiAgICAgIHF1ZXJ5Q2xpZW50LmludmFsaWRhdGVRdWVyaWVzKHtxdWVyeUtleTogd2FsbGV0S2V5cy5hbGx9KVxuICAgICAgcXVlcnlDbGllbnQuaW52YWxpZGF0ZVF1ZXJpZXMoe3F1ZXJ5S2V5OiB3YWxsZXRLZXlzLnJlZGVtcHRpb25zKCl9KVxuICAgIH0sXG4gIH0pXG59XG4iXX0=
@@ -24,3 +24,5 @@ export * from './products';
24
24
  export { productKeys } from './products';
25
25
  export * from './orders';
26
26
  export { orderKeys } from './orders';
27
+ export * from './wallet';
28
+ export { walletKeys } from './wallet';
@@ -19,7 +19,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
19
19
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
20
20
  };
21
21
  Object.defineProperty(exports, "__esModule", { value: true });
22
- exports.orderKeys = exports.productKeys = exports.miscKeys = exports.notificationKeys = exports.templateKeys = exports.clubKeys = exports.conversationKeys = exports.postKeys = exports.spotKeys = exports.userKeys = void 0;
22
+ exports.walletKeys = exports.orderKeys = exports.productKeys = exports.miscKeys = exports.notificationKeys = exports.templateKeys = exports.clubKeys = exports.conversationKeys = exports.postKeys = exports.spotKeys = exports.userKeys = void 0;
23
23
  // Auth (mutations, but grouped with queries for convenience)
24
24
  __exportStar(require("./auth"), exports);
25
25
  // Users
@@ -62,4 +62,8 @@ Object.defineProperty(exports, "productKeys", { enumerable: true, get: function
62
62
  __exportStar(require("./orders"), exports);
63
63
  var orders_1 = require("./orders");
64
64
  Object.defineProperty(exports, "orderKeys", { enumerable: true, get: function () { return orders_1.orderKeys; } });
65
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpL3F1ZXJpZXMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7O0dBSUc7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRUgsNkRBQTZEO0FBQzdELHlDQUFzQjtBQUV0QixRQUFRO0FBQ1IsMENBQXVCO0FBQ3ZCLGlDQUFnQztBQUF4QixpR0FBQSxRQUFRLE9BQUE7QUFFaEIsUUFBUTtBQUNSLDBDQUF1QjtBQUN2QixpQ0FBZ0M7QUFBeEIsaUdBQUEsUUFBUSxPQUFBO0FBRWhCLFFBQVE7QUFDUiwwQ0FBdUI7QUFDdkIsaUNBQWdDO0FBQXhCLGlHQUFBLFFBQVEsT0FBQTtBQUVoQixnQkFBZ0I7QUFDaEIsa0RBQStCO0FBQy9CLGlEQUFnRDtBQUF4QyxpSEFBQSxnQkFBZ0IsT0FBQTtBQUV4QixRQUFRO0FBQ1IsMENBQXVCO0FBQ3ZCLGlDQUFnQztBQUF4QixpR0FBQSxRQUFRLE9BQUE7QUFFaEIsWUFBWTtBQUNaLDhDQUEyQjtBQUMzQix5Q0FBd0M7QUFBaEMseUdBQUEsWUFBWSxPQUFBO0FBRXBCLGdCQUFnQjtBQUNoQixrREFBK0I7QUFDL0IsaURBQWdEO0FBQXhDLGlIQUFBLGdCQUFnQixPQUFBO0FBRXhCLCtCQUErQjtBQUMvQix5Q0FBc0I7QUFDdEIsK0JBQStCO0FBQXZCLGdHQUFBLFFBQVEsT0FBQTtBQUVoQix5QkFBeUI7QUFDekIsNkNBQTBCO0FBQzFCLHVDQUFzQztBQUE5Qix1R0FBQSxXQUFXLE9BQUE7QUFFbkIsdUJBQXVCO0FBQ3ZCLDJDQUF3QjtBQUN4QixtQ0FBa0M7QUFBMUIsbUdBQUEsU0FBUyxPQUFBIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBTcG90cyBTREsgUXVlcnkgSG9va3MgSW5kZXhcbiAqXG4gKiBSZS1leHBvcnRzIGFsbCBxdWVyeSBob29rcyBhbmQga2V5cy5cbiAqL1xuXG4vLyBBdXRoIChtdXRhdGlvbnMsIGJ1dCBncm91cGVkIHdpdGggcXVlcmllcyBmb3IgY29udmVuaWVuY2UpXG5leHBvcnQgKiBmcm9tICcuL2F1dGgnXG5cbi8vIFVzZXJzXG5leHBvcnQgKiBmcm9tICcuL3VzZXJzJ1xuZXhwb3J0IHt1c2VyS2V5c30gZnJvbSAnLi91c2VycydcblxuLy8gU3BvdHNcbmV4cG9ydCAqIGZyb20gJy4vc3BvdHMnXG5leHBvcnQge3Nwb3RLZXlzfSBmcm9tICcuL3Nwb3RzJ1xuXG4vLyBQb3N0c1xuZXhwb3J0ICogZnJvbSAnLi9wb3N0cydcbmV4cG9ydCB7cG9zdEtleXN9IGZyb20gJy4vcG9zdHMnXG5cbi8vIENvbnZlcnNhdGlvbnNcbmV4cG9ydCAqIGZyb20gJy4vY29udmVyc2F0aW9ucydcbmV4cG9ydCB7Y29udmVyc2F0aW9uS2V5c30gZnJvbSAnLi9jb252ZXJzYXRpb25zJ1xuXG4vLyBDbHVic1xuZXhwb3J0ICogZnJvbSAnLi9jbHVicydcbmV4cG9ydCB7Y2x1YktleXN9IGZyb20gJy4vY2x1YnMnXG5cbi8vIFRlbXBsYXRlc1xuZXhwb3J0ICogZnJvbSAnLi90ZW1wbGF0ZXMnXG5leHBvcnQge3RlbXBsYXRlS2V5c30gZnJvbSAnLi90ZW1wbGF0ZXMnXG5cbi8vIE5vdGlmaWNhdGlvbnNcbmV4cG9ydCAqIGZyb20gJy4vbm90aWZpY2F0aW9ucydcbmV4cG9ydCB7bm90aWZpY2F0aW9uS2V5c30gZnJvbSAnLi9ub3RpZmljYXRpb25zJ1xuXG4vLyBNaXNjIChjaXRpZXMsIHZpYmVzLCBldmVudHMpXG5leHBvcnQgKiBmcm9tICcuL21pc2MnXG5leHBvcnQge21pc2NLZXlzfSBmcm9tICcuL21pc2MnXG5cbi8vIFByb2R1Y3RzIChtYXJrZXRwbGFjZSlcbmV4cG9ydCAqIGZyb20gJy4vcHJvZHVjdHMnXG5leHBvcnQge3Byb2R1Y3RLZXlzfSBmcm9tICcuL3Byb2R1Y3RzJ1xuXG4vLyBPcmRlcnMgKG1hcmtldHBsYWNlKVxuZXhwb3J0ICogZnJvbSAnLi9vcmRlcnMnXG5leHBvcnQge29yZGVyS2V5c30gZnJvbSAnLi9vcmRlcnMnXG4iXX0=
65
+ // Wallet (redemptions)
66
+ __exportStar(require("./wallet"), exports);
67
+ var wallet_1 = require("./wallet");
68
+ Object.defineProperty(exports, "walletKeys", { enumerable: true, get: function () { return wallet_1.walletKeys; } });
69
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpL3F1ZXJpZXMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7O0dBSUc7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRUgsNkRBQTZEO0FBQzdELHlDQUFzQjtBQUV0QixRQUFRO0FBQ1IsMENBQXVCO0FBQ3ZCLGlDQUFnQztBQUF4QixpR0FBQSxRQUFRLE9BQUE7QUFFaEIsUUFBUTtBQUNSLDBDQUF1QjtBQUN2QixpQ0FBZ0M7QUFBeEIsaUdBQUEsUUFBUSxPQUFBO0FBRWhCLFFBQVE7QUFDUiwwQ0FBdUI7QUFDdkIsaUNBQWdDO0FBQXhCLGlHQUFBLFFBQVEsT0FBQTtBQUVoQixnQkFBZ0I7QUFDaEIsa0RBQStCO0FBQy9CLGlEQUFnRDtBQUF4QyxpSEFBQSxnQkFBZ0IsT0FBQTtBQUV4QixRQUFRO0FBQ1IsMENBQXVCO0FBQ3ZCLGlDQUFnQztBQUF4QixpR0FBQSxRQUFRLE9BQUE7QUFFaEIsWUFBWTtBQUNaLDhDQUEyQjtBQUMzQix5Q0FBd0M7QUFBaEMseUdBQUEsWUFBWSxPQUFBO0FBRXBCLGdCQUFnQjtBQUNoQixrREFBK0I7QUFDL0IsaURBQWdEO0FBQXhDLGlIQUFBLGdCQUFnQixPQUFBO0FBRXhCLCtCQUErQjtBQUMvQix5Q0FBc0I7QUFDdEIsK0JBQStCO0FBQXZCLGdHQUFBLFFBQVEsT0FBQTtBQUVoQix5QkFBeUI7QUFDekIsNkNBQTBCO0FBQzFCLHVDQUFzQztBQUE5Qix1R0FBQSxXQUFXLE9BQUE7QUFFbkIsdUJBQXVCO0FBQ3ZCLDJDQUF3QjtBQUN4QixtQ0FBa0M7QUFBMUIsbUdBQUEsU0FBUyxPQUFBO0FBRWpCLHVCQUF1QjtBQUN2QiwyQ0FBd0I7QUFDeEIsbUNBQW1DO0FBQTNCLG9HQUFBLFVBQVUsT0FBQSIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU3BvdHMgU0RLIFF1ZXJ5IEhvb2tzIEluZGV4XG4gKlxuICogUmUtZXhwb3J0cyBhbGwgcXVlcnkgaG9va3MgYW5kIGtleXMuXG4gKi9cblxuLy8gQXV0aCAobXV0YXRpb25zLCBidXQgZ3JvdXBlZCB3aXRoIHF1ZXJpZXMgZm9yIGNvbnZlbmllbmNlKVxuZXhwb3J0ICogZnJvbSAnLi9hdXRoJ1xuXG4vLyBVc2Vyc1xuZXhwb3J0ICogZnJvbSAnLi91c2VycydcbmV4cG9ydCB7dXNlcktleXN9IGZyb20gJy4vdXNlcnMnXG5cbi8vIFNwb3RzXG5leHBvcnQgKiBmcm9tICcuL3Nwb3RzJ1xuZXhwb3J0IHtzcG90S2V5c30gZnJvbSAnLi9zcG90cydcblxuLy8gUG9zdHNcbmV4cG9ydCAqIGZyb20gJy4vcG9zdHMnXG5leHBvcnQge3Bvc3RLZXlzfSBmcm9tICcuL3Bvc3RzJ1xuXG4vLyBDb252ZXJzYXRpb25zXG5leHBvcnQgKiBmcm9tICcuL2NvbnZlcnNhdGlvbnMnXG5leHBvcnQge2NvbnZlcnNhdGlvbktleXN9IGZyb20gJy4vY29udmVyc2F0aW9ucydcblxuLy8gQ2x1YnNcbmV4cG9ydCAqIGZyb20gJy4vY2x1YnMnXG5leHBvcnQge2NsdWJLZXlzfSBmcm9tICcuL2NsdWJzJ1xuXG4vLyBUZW1wbGF0ZXNcbmV4cG9ydCAqIGZyb20gJy4vdGVtcGxhdGVzJ1xuZXhwb3J0IHt0ZW1wbGF0ZUtleXN9IGZyb20gJy4vdGVtcGxhdGVzJ1xuXG4vLyBOb3RpZmljYXRpb25zXG5leHBvcnQgKiBmcm9tICcuL25vdGlmaWNhdGlvbnMnXG5leHBvcnQge25vdGlmaWNhdGlvbktleXN9IGZyb20gJy4vbm90aWZpY2F0aW9ucydcblxuLy8gTWlzYyAoY2l0aWVzLCB2aWJlcywgZXZlbnRzKVxuZXhwb3J0ICogZnJvbSAnLi9taXNjJ1xuZXhwb3J0IHttaXNjS2V5c30gZnJvbSAnLi9taXNjJ1xuXG4vLyBQcm9kdWN0cyAobWFya2V0cGxhY2UpXG5leHBvcnQgKiBmcm9tICcuL3Byb2R1Y3RzJ1xuZXhwb3J0IHtwcm9kdWN0S2V5c30gZnJvbSAnLi9wcm9kdWN0cydcblxuLy8gT3JkZXJzIChtYXJrZXRwbGFjZSlcbmV4cG9ydCAqIGZyb20gJy4vb3JkZXJzJ1xuZXhwb3J0IHtvcmRlcktleXN9IGZyb20gJy4vb3JkZXJzJ1xuXG4vLyBXYWxsZXQgKHJlZGVtcHRpb25zKVxuZXhwb3J0ICogZnJvbSAnLi93YWxsZXQnXG5leHBvcnQge3dhbGxldEtleXN9IGZyb20gJy4vd2FsbGV0J1xuIl19
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Wallet Query Hooks
3
+ *
4
+ * TanStack Query hooks for wallet and redemption operations.
5
+ */
6
+ import { type UseQueryOptions, type UseQueryResult } from '@tanstack/react-query';
7
+ export type RedemptionStatus = 'PENDING' | 'REDEEMED' | 'EXPIRED' | 'CANCELLED' | 'VOID';
8
+ export interface WalletProduct {
9
+ id: string;
10
+ name: string;
11
+ type: string;
12
+ imageUrl: string | null;
13
+ }
14
+ export interface WalletOrderItem {
15
+ product: WalletProduct;
16
+ quantity: number;
17
+ unitPrice: number;
18
+ }
19
+ export interface WalletOrder {
20
+ id: string;
21
+ orderNumber: string;
22
+ spotId: string;
23
+ createdAt: string;
24
+ spot: {
25
+ id: string;
26
+ name: string;
27
+ slug: string;
28
+ address: string | null;
29
+ };
30
+ }
31
+ export interface WalletRedemption {
32
+ id: string;
33
+ qrCode: string;
34
+ qrCodeUrl: string | null;
35
+ status: RedemptionStatus;
36
+ validFrom: string;
37
+ validUntil: string;
38
+ redeemedAt: string | null;
39
+ createdAt: string;
40
+ orderItem: WalletOrderItem & {
41
+ order: WalletOrder;
42
+ };
43
+ }
44
+ export interface RedemptionLookup extends WalletRedemption {
45
+ redeemedBy: {
46
+ id: string;
47
+ name: string;
48
+ } | null;
49
+ spot: {
50
+ id: string;
51
+ name: string;
52
+ } | null;
53
+ orderItem: WalletOrderItem & {
54
+ order: WalletOrder & {
55
+ user: {
56
+ id: string;
57
+ name: string | null;
58
+ avatarUrl: string | null;
59
+ };
60
+ };
61
+ };
62
+ }
63
+ export interface WalletHistoryResponse {
64
+ data: WalletRedemption[];
65
+ meta: {
66
+ total: number;
67
+ page: number;
68
+ limit: number;
69
+ totalPages: number;
70
+ };
71
+ }
72
+ export declare const walletKeys: {
73
+ all: readonly ["wallet"];
74
+ active: () => readonly ["wallet", "active"];
75
+ history: (page?: number) => readonly ["wallet", "history", number | undefined];
76
+ redemptions: () => readonly ["redemptions"];
77
+ lookup: (qrCode: string) => readonly ["redemptions", "lookup", string];
78
+ spotRedemptions: (spotId: string, page?: number) => readonly ["redemptions", "spot", string, number | undefined];
79
+ };
80
+ /**
81
+ * Get user's active wallet items (pending redemptions)
82
+ *
83
+ * @endpoint GET /wallet
84
+ */
85
+ export declare function useWallet(options?: Omit<UseQueryOptions<WalletRedemption[]>, 'queryKey' | 'queryFn'>): UseQueryResult<WalletRedemption[]>;
86
+ /**
87
+ * Get user's wallet history (all redemptions)
88
+ *
89
+ * @endpoint GET /wallet/history
90
+ */
91
+ export declare function useWalletHistory(params?: {
92
+ page?: number;
93
+ limit?: number;
94
+ }, options?: Omit<UseQueryOptions<WalletHistoryResponse>, 'queryKey' | 'queryFn'>): UseQueryResult<WalletHistoryResponse>;
95
+ /**
96
+ * Lookup redemption by QR code (for scanner)
97
+ *
98
+ * @endpoint GET /redemptions/lookup/:qrCode
99
+ */
100
+ export declare function useRedemptionLookup(qrCode: string, options?: Omit<UseQueryOptions<RedemptionLookup>, 'queryKey' | 'queryFn'>): UseQueryResult<RedemptionLookup>;
101
+ /**
102
+ * Get spot's redemption history (for spot owner)
103
+ *
104
+ * @endpoint GET /spots/:spotId/redemptions
105
+ */
106
+ export declare function useSpotRedemptions(spotId: string, params?: {
107
+ page?: number;
108
+ limit?: number;
109
+ }, options?: Omit<UseQueryOptions<WalletHistoryResponse>, 'queryKey' | 'queryFn'>): UseQueryResult<WalletHistoryResponse>;
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ /**
3
+ * Wallet Query Hooks
4
+ *
5
+ * TanStack Query hooks for wallet and redemption operations.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.walletKeys = void 0;
9
+ exports.useWallet = useWallet;
10
+ exports.useWalletHistory = useWalletHistory;
11
+ exports.useRedemptionLookup = useRedemptionLookup;
12
+ exports.useSpotRedemptions = useSpotRedemptions;
13
+ const react_query_1 = require("@tanstack/react-query");
14
+ const client_1 = require("../client");
15
+ // ============================================================================
16
+ // HELPER FUNCTIONS
17
+ // ============================================================================
18
+ function extractArrayData(data) {
19
+ if (Array.isArray(data)) {
20
+ return data;
21
+ }
22
+ if (data && typeof data === 'object' && 'data' in data) {
23
+ const nested = data.data;
24
+ if (Array.isArray(nested)) {
25
+ return nested;
26
+ }
27
+ }
28
+ return [];
29
+ }
30
+ function extractObjectData(data) {
31
+ if (data &&
32
+ typeof data === 'object' &&
33
+ 'data' in data &&
34
+ !Array.isArray(data)) {
35
+ const nested = data.data;
36
+ if (nested &&
37
+ typeof nested === 'object' &&
38
+ 'data' in nested &&
39
+ !Array.isArray(nested)) {
40
+ return nested.data;
41
+ }
42
+ return nested;
43
+ }
44
+ return data;
45
+ }
46
+ // ============================================================================
47
+ // QUERY KEYS
48
+ // ============================================================================
49
+ exports.walletKeys = {
50
+ all: ['wallet'],
51
+ active: () => [...exports.walletKeys.all, 'active'],
52
+ history: (page) => [...exports.walletKeys.all, 'history', page],
53
+ redemptions: () => ['redemptions'],
54
+ lookup: (qrCode) => [...exports.walletKeys.redemptions(), 'lookup', qrCode],
55
+ spotRedemptions: (spotId, page) => [...exports.walletKeys.redemptions(), 'spot', spotId, page],
56
+ };
57
+ // ============================================================================
58
+ // QUERY HOOKS
59
+ // ============================================================================
60
+ /**
61
+ * Get user's active wallet items (pending redemptions)
62
+ *
63
+ * @endpoint GET /wallet
64
+ */
65
+ function useWallet(options) {
66
+ return (0, react_query_1.useQuery)({
67
+ queryKey: exports.walletKeys.active(),
68
+ queryFn: async () => {
69
+ const client = (0, client_1.getApiClient)();
70
+ const response = await client.get('/wallet');
71
+ return extractArrayData(response.data.data);
72
+ },
73
+ ...options,
74
+ });
75
+ }
76
+ /**
77
+ * Get user's wallet history (all redemptions)
78
+ *
79
+ * @endpoint GET /wallet/history
80
+ */
81
+ function useWalletHistory(params, options) {
82
+ return (0, react_query_1.useQuery)({
83
+ queryKey: exports.walletKeys.history(params?.page),
84
+ queryFn: async () => {
85
+ const client = (0, client_1.getApiClient)();
86
+ const queryParams = new URLSearchParams();
87
+ if (params?.page)
88
+ queryParams.set('page', String(params.page));
89
+ if (params?.limit)
90
+ queryParams.set('limit', String(params.limit));
91
+ const response = await client.get(`/wallet/history?${queryParams}`);
92
+ return extractObjectData(response.data.data);
93
+ },
94
+ ...options,
95
+ });
96
+ }
97
+ /**
98
+ * Lookup redemption by QR code (for scanner)
99
+ *
100
+ * @endpoint GET /redemptions/lookup/:qrCode
101
+ */
102
+ function useRedemptionLookup(qrCode, options) {
103
+ return (0, react_query_1.useQuery)({
104
+ queryKey: exports.walletKeys.lookup(qrCode),
105
+ queryFn: async () => {
106
+ const client = (0, client_1.getApiClient)();
107
+ const response = await client.get(`/redemptions/lookup/${qrCode}`);
108
+ return extractObjectData(response.data.data);
109
+ },
110
+ enabled: !!qrCode && qrCode.length > 0,
111
+ ...options,
112
+ });
113
+ }
114
+ /**
115
+ * Get spot's redemption history (for spot owner)
116
+ *
117
+ * @endpoint GET /spots/:spotId/redemptions
118
+ */
119
+ function useSpotRedemptions(spotId, params, options) {
120
+ return (0, react_query_1.useQuery)({
121
+ queryKey: exports.walletKeys.spotRedemptions(spotId, params?.page),
122
+ queryFn: async () => {
123
+ const client = (0, client_1.getApiClient)();
124
+ const queryParams = new URLSearchParams();
125
+ if (params?.page)
126
+ queryParams.set('page', String(params.page));
127
+ if (params?.limit)
128
+ queryParams.set('limit', String(params.limit));
129
+ const response = await client.get(`/spots/${spotId}/redemptions?${queryParams}`);
130
+ return extractObjectData(response.data.data);
131
+ },
132
+ enabled: !!spotId,
133
+ ...options,
134
+ });
135
+ }
136
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2FsbGV0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FwaS9xdWVyaWVzL3dhbGxldC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7R0FJRzs7O0FBb0pILDhCQVlDO0FBT0QsNENBa0JDO0FBT0Qsa0RBZ0JDO0FBT0QsZ0RBb0JDO0FBek9ELHVEQUk4QjtBQUU5QixzQ0FBc0M7QUErRXRDLCtFQUErRTtBQUMvRSxtQkFBbUI7QUFDbkIsK0VBQStFO0FBRS9FLFNBQVMsZ0JBQWdCLENBQUksSUFBYTtJQUN4QyxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztRQUN4QixPQUFPLElBQUksQ0FBQTtJQUNiLENBQUM7SUFDRCxJQUFJLElBQUksSUFBSSxPQUFPLElBQUksS0FBSyxRQUFRLElBQUksTUFBTSxJQUFJLElBQUksRUFBRSxDQUFDO1FBQ3ZELE1BQU0sTUFBTSxHQUFJLElBQXdCLENBQUMsSUFBSSxDQUFBO1FBQzdDLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1lBQzFCLE9BQU8sTUFBTSxDQUFBO1FBQ2YsQ0FBQztJQUNILENBQUM7SUFDRCxPQUFPLEVBQUUsQ0FBQTtBQUNYLENBQUM7QUFFRCxTQUFTLGlCQUFpQixDQUFJLElBQWE7SUFDekMsSUFDRSxJQUFJO1FBQ0osT0FBTyxJQUFJLEtBQUssUUFBUTtRQUN4QixNQUFNLElBQUksSUFBSTtRQUNkLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFDcEIsQ0FBQztRQUNELE1BQU0sTUFBTSxHQUFJLElBQXdCLENBQUMsSUFBSSxDQUFBO1FBQzdDLElBQ0UsTUFBTTtZQUNOLE9BQU8sTUFBTSxLQUFLLFFBQVE7WUFDMUIsTUFBTSxJQUFJLE1BQU07WUFDaEIsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUN0QixDQUFDO1lBQ0QsT0FBUSxN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QUMsQ0FBQTtRQUNyRSxDQUFDO1FBQ0QsT0FBTyxFQUFFLENBQUMsQ0FBQyxNQUFNO1FBQ2pCLEdBQUcsT0FBTztLQUNYLENBQUMsQ0FBQTtBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFdhbGxldCBRdWVyeSBIb29rc1xuICpcbiAqIFRhblN0YWNrIFF1ZXJ5IGhvb2tzIGZvciB3YWxsZXQgYW5kIHJlZGVtcHRpb24gb3BlcmF0aW9ucy5cbiAqL1xuXG5pbXBvcnQge1xuICB1c2VRdWVyeSxcbiAgdHlwZSBVc2VRdWVyeU9wdGlvbnMsXG4gIHR5cGUgVXNlUXVlcnlSZXN1bHQsXG59IGZyb20gJ0B0YW5zdGFjay9yZWFjdC1xdWVyeSdcblxuaW1wb3J0IHtnZXRBcGlDbGllbnR9IGZyb20gJy4uL2NsaWVudCdcbmltcG9ydCB7dHlwZSBBcGlSZXNwb25zZX0gZnJvbSAnLi4vdHlwZXMnXG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIFRZUEVTXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmV4cG9ydCB0eXBlIFJlZGVtcHRpb25TdGF0dXMgPSAnUEVORElORycgfCAnUkVERUVNRUQnIHwgJ0VYUElSRUQnIHwgJ0NBTkNFTExFRCcgfCAnVk9JRCdcblxuZXhwb3J0IGludGVyZmFjZSBXYWxsZXRQcm9kdWN0IHtcbiAgaWQ6IHN0cmluZ1xuICBuYW1lOiBzdHJpbmdcbiAgdHlwZTogc3RyaW5nXG4gIGltYWdlVXJsOiBzdHJpbmcgfCBudWxsXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgV2FsbGV0T3JkZXJJdGVtIHtcbiAgcHJvZHVjdDogV2FsbGV0UHJvZHVjdFxuICBxdWFudGl0eTogbnVtYmVyXG4gIHVuaXRQcmljZTogbnVtYmVyXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgV2FsbGV0T3JkZXIge1xuICBpZDogc3RyaW5nXG4gIG9yZGVyTnVtYmVyOiBzdHJpbmdcbiAgc3BvdElkOiBzdHJpbmdcbiAgY3JlYXRlZEF0OiBzdHJpbmdcbiAgc3BvdDoge1xuICAgIGlkOiBzdHJpbmdcbiAgICBuYW1lOiBzdHJpbmdcbiAgICBzbHVnOiBzdHJpbmdcbiAgICBhZGRyZXNzOiBzdHJpbmcgfCBudWxsXG4gIH1cbn1cblxuZXhwb3J0IGludGVyZmFjZSBXYWxsZXRSZWRlbXB0aW9uIHtcbiAgaWQ6IHN0cmluZ1xuICBxckNvZGU6IHN0cmluZ1xuICBxckNvZGVVcmw6IHN0cmluZyB8IG51bGxcbiAgc3RhdHVzOiBSZWRlbXB0aW9uU3RhdHVzXG4gIHZhbGlkRnJvbTogc3RyaW5nXG4gIHZhbGlkVW50aWw6IHN0cmluZ1xuICByZWRlZW1lZEF0OiBzdHJpbmcgfCBudWxsXG4gIGNyZWF0ZWRBdDogc3RyaW5nXG4gIG9yZGVySXRlbTogV2FsbGV0T3JkZXJJdGVtICYge1xuICAgIG9yZGVyOiBXYWxsZXRPcmRlclxuICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVkZW1wdGlvbkxvb2t1cCBleHRlbmRzIFdhbGxldFJlZGVtcHRpb24ge1xuICByZWRlZW1lZEJ5OiB7XG4gICAgaWQ6IHN0cmluZ1xuICAgIG5hbWU6IHN0cmluZ1xuICB9IHwgbnVsbFxuICBzcG90OiB7XG4gICAgaWQ6IHN0cmluZ1xuICAgIG5hbWU6IHN0cmluZ1xuICB9IHwgbnVsbFxuICBvcmRlckl0ZW06IFdhbGxldE9yZGVySXRlbSAmIHtcbiAgICBvcmRlcjogV2FsbGV0T3JkZXIgJiB7XG4gICAgICB1c2VyOiB7XG4gICAgICAgIGlkOiBzdHJpbmdcbiAgICAgICAgbmFtZTogc3RyaW5nIHwgbnVsbFxuICAgICAgICBhdmF0YXJVcmw6IHN0cmluZyB8IG51bGxcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuZXhwb3J0IGludGVyZmFjZSBXYWxsZXRIaXN0b3J5UmVzcG9uc2Uge1xuICBkYXRhOiBXYWxsZXRSZWRlbXB0aW9uW11cbiAgbWV0YToge1xuICAgIHRvdGFsOiBudW1iZXJcbiAgICBwYWdlOiBudW1iZXJcbiAgICBsaW1pdDogbnVtYmVyXG4gICAgdG90YWxQYWdlczogbnVtYmVyXG4gIH1cbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gSEVMUEVSIEZVTkNUSU9OU1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5mdW5jdGlvbiBleHRyYWN0QXJyYXlEYXRhPFQ+KGRhdGE6IHVua25vd24pOiBUW10ge1xuICBpZiAoQXJyYXkuaXNBcnJheShkYXRhKSkge1xuICAgIHJldHVybiBkYXRhXG4gIH1cbiAgaWYgKGRhdGEgJiYgdHlwZW9mIGRhdGEgPT09ICdvYmplY3QnICYmICdkYXRhJyBpbiBkYXRhKSB7XG4gICAgY29uc3QgbmVzdGVkID0gKGRhdGEgYXMge2RhdGE6IHVua25vd259KS5kYXRhXG4gICAgaWYgKEFycmF5LmlzQXJyYXkobmVzdGVkKSkge1xuICAgICAgcmV0dXJuIG5lc3RlZFxuICAgIH1cbiAgfVxuICByZXR1cm4gW11cbn1cblxuZnVuY3Rpb24gZXh0cmFjdE9iamVjdERhdGE8VD4oZGF0YTogdW5rbm93bik6IFQge1xuICBpZiAoXG4gICAgZGF0YSAmJlxuICAgIHR5cGVvZiBkYXRhID09PSAnb2JqZWN0JyAmJlxuICAgICdkYXRhJyBpbiBkYXRhICYmXG4gICAgIUFycmF5LmlzQXJyYXkoZGF0YSlcbiAgKSB7XG4gICAgY29uc3QgbmVzdGVkID0gKGRhdGEgYXMge2RhdGE6IHVua25vd259KS5kYXRhXG4gICAgaWYgKFxuICAgICAgbmVzdGVkICYmXG4gICAgICB0eXBlb2YgbmVzdGVkID09PSAnb2JqZWN0JyAmJlxuICAgICAgJ2RhdGEnIGluIG5lc3RlZCAmJlxuICAgICAgIUFycmF5LmlzQXJyYXkobmVzdGVkKVxuICAgICkge1xuICAgICAgcmV0dXJuIChuZXN0ZWQgYXMge2RhdGE6IFR9KS5kYXRhXG4gICAgfVxuICAgIHJldHVybiBuZXN0ZWQgYXMgVFxuICB9XG4gIHJldHVybiBkYXRhIGFzIFRcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gUVVFUlkgS0VZU1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgY29uc3Qgd2FsbGV0S2V5cyA9IHtcbiAgYWxsOiBbJ3dhbGxldCddIGFzIGNvbnN0LFxuICBhY3RpdmU6ICgpID0+IFsuLi53YWxsZXRLZXlzLmFsbCwgJ2FjdGl2ZSddIGFzIGNvbnN0LFxuICBoaXN0b3J5OiAocGFnZT86IG51bWJlcikgPT4gWy4uLndhbGxldEtleXMuYWxsLCAnaGlzdG9yeScsIHBhZ2VdIGFzIGNvbnN0LFxuICByZWRlbXB0aW9uczogKCkgPT4gWydyZWRlbXB0aW9ucyddIGFzIGNvbnN0LFxuICBsb29rdXA6IChxckNvZGU6IHN0cmluZykgPT4gWy4uLndhbGxldEtleXMucmVkZW1wdGlvbnMoKSwgJ2xvb2t1cCcsIHFyQ29kZV0gYXMgY29uc3QsXG4gIHNwb3RSZWRlbXB0aW9uczogKHNwb3RJZDogc3RyaW5nLCBwYWdlPzogbnVtYmVyKSA9PlxuICAgIFsuLi53YWxsZXRLZXlzLnJlZGVtcHRpb25zKCksICdzcG90Jywgc3BvdElkLCBwYWdlXSBhcyBjb25zdCxcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gUVVFUlkgSE9PS1Ncbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLyoqXG4gKiBHZXQgdXNlcidzIGFjdGl2ZSB3YWxsZXQgaXRlbXMgKHBlbmRpbmcgcmVkZW1wdGlvbnMpXG4gKlxuICogQGVuZHBvaW50IEdFVCAvd2FsbGV0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1c2VXYWxsZXQoXG4gIG9wdGlvbnM/OiBPbWl0PFVzZVF1ZXJ5T3B0aW9uczxXYWxsZXRSZWRlbXB0aW9uW10+LCAncXVlcnlLZXknIHwgJ3F1ZXJ5Rm4nPixcbik6IFVzZVF1ZXJ5UmVzdWx0PFdhbGxldFJlZGVtcHRpb25bXT4ge1xuICByZXR1cm4gdXNlUXVlcnkoe1xuICAgIHF1ZXJ5S2V5OiB3YWxsZXRLZXlzLmFjdGl2ZSgpLFxuICAgIHF1ZXJ5Rm46IGFzeW5jICgpOiBQcm9taXNlPFdhbGxldFJlZGVtcHRpb25bXT4gPT4ge1xuICAgICAgY29uc3QgY2xpZW50ID0gZ2V0QXBpQ2xpZW50KClcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2xpZW50LmdldDxBcGlSZXNwb25zZTx1bmtub3duPj4oJy93YWxsZXQnKVxuICAgICAgcmV0dXJuIGV4dHJhY3RBcnJheURhdGE8V2FsbGV0UmVkZW1wdGlvbj4ocmVzcG9uc2UuZGF0YS5kYXRhKVxuICAgIH0sXG4gICAgLi4ub3B0aW9ucyxcbiAgfSlcbn1cblxuLyoqXG4gKiBHZXQgdXNlcidzIHdhbGxldCBoaXN0b3J5IChhbGwgcmVkZW1wdGlvbnMpXG4gKlxuICogQGVuZHBvaW50IEdFVCAvd2FsbGV0L2hpc3RvcnlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVzZVdhbGxldEhpc3RvcnkoXG4gIHBhcmFtcz86IHtwYWdlPzogbnVtYmVyOyBsaW1pdD86IG51bWJlcn0sXG4gIG9wdGlvbnM/OiBPbWl0PFVzZVF1ZXJ5T3B0aW9uczxXYWxsZXRIaXN0b3J5UmVzcG9uc2U+LCAncXVlcnlLZXknIHwgJ3F1ZXJ5Rm4nPixcbik6IFVzZVF1ZXJ5UmVzdWx0PFdhbGxldEhpc3RvcnlSZXNwb25zZT4ge1xuICByZXR1cm4gdXNlUXVlcnkoe1xuICAgIHF1ZXJ5S2V5OiB3YWxsZXRLZXlzLmhpc3RvcnkocGFyYW1zPy5wYWdlKSxcbiAgICBxdWVyeUZuOiBhc3luYyAoKTogUHJvbWlzZTxXYWxsZXRIaXN0b3J5UmVzcG9uc2U+ID0+IHtcbiAgICAgIGNvbnN0IGNsaWVudCA9IGdldEFwaUNsaWVudCgpXG4gICAgICBjb25zdCBxdWVyeVBhcmFtcyA9IG5ldyBVUkxTZWFyY2hQYXJhbXMoKVxuICAgICAgaWYgKHBhcmFtcz8ucGFnZSkgcXVlcnlQYXJhbXMuc2V0KCdwYWdlJywgU3RyaW5nKHBhcmFtcy5wYWdlKSlcbiAgICAgIGlmIChwYXJhbXM/LmxpbWl0KSBxdWVyeVBhcmFtcy5zZXQoJ2xpbWl0JywgU3RyaW5nKHBhcmFtcy5saW1pdCkpXG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGNsaWVudC5nZXQ8QXBpUmVzcG9uc2U8V2FsbGV0SGlzdG9yeVJlc3BvbnNlPj4oXG4gICAgICAgIGAvd2FsbGV0L2hpc3Rvcnk/JHtxdWVyeVBhcmFtc31gLFxuICAgICAgKVxuICAgICAgcmV0dXJuIGV4dHJhY3RPYmplY3REYXRhPFdhbGxldEhpc3RvcnlSZXNwb25zZT4ocmVzcG9uc2UuZGF0YS5kYXRhKVxuICAgIH0sXG4gICAgLi4ub3B0aW9ucyxcbiAgfSlcbn1cblxuLyoqXG4gKiBMb29rdXAgcmVkZW1wdGlvbiBieSBRUiBjb2RlIChmb3Igc2Nhbm5lcilcbiAqXG4gKiBAZW5kcG9pbnQgR0VUIC9yZWRlbXB0aW9ucy9sb29rdXAvOnFyQ29kZVxuICovXG5leHBvcnQgZnVuY3Rpb24gdXNlUmVkZW1wdGlvbkxvb2t1cChcbiAgcXJDb2RlOiBzdHJpbmcsXG4gIG9wdGlvbnM/OiBPbWl0PFVzZVF1ZXJ5T3B0aW9uczxSZWRlbXB0aW9uTG9va3VwPiwgJ3F1ZXJ5S2V5JyB8ICdxdWVyeUZuJz4sXG4pOiBVc2VRdWVyeVJlc3VsdDxSZWRlbXB0aW9uTG9va3VwPiB7XG4gIHJldHVybiB1c2VRdWVyeSh7XG4gICAgcXVlcnlLZXk6IHdhbGxldEtleXMubG9va3VwKHFyQ29kZSksXG4gICAgcXVlcnlGbjogYXN5bmMgKCk6IFByb21pc2U8UmVkZW1wdGlvbkxvb2t1cD4gPT4ge1xuICAgICAgY29uc3QgY2xpZW50ID0gZ2V0QXBpQ2xpZW50KClcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2xpZW50LmdldDxBcGlSZXNwb25zZTx1bmtub3duPj4oXG4gICAgICAgIGAvcmVkZW1wdGlvbnMvbG9va3VwLyR7cXJDb2RlfWAsXG4gICAgICApXG4gICAgICByZXR1cm4gZXh0cmFjdE9iamVjdERhdGE8UmVkZW1wdGlvbkxvb2t1cD4ocmVzcG9uc2UuZGF0YS5kYXRhKVxuICAgIH0sXG4gICAgZW5hYmxlZDogISFxckNvZGUgJiYgcXJDb2RlLmxlbmd0aCA+IDAsXG4gICAgLi4ub3B0aW9ucyxcbiAgfSlcbn1cblxuLyoqXG4gKiBHZXQgc3BvdCdzIHJlZGVtcHRpb24gaGlzdG9yeSAoZm9yIHNwb3Qgb3duZXIpXG4gKlxuICogQGVuZHBvaW50IEdFVCAvc3BvdHMvOnNwb3RJZC9yZWRlbXB0aW9uc1xuICovXG5leHBvcnQgZnVuY3Rpb24gdXNlU3BvdFJlZGVtcHRpb25zKFxuICBzcG90SWQ6IHN0cmluZyxcbiAgcGFyYW1zPzoge3BhZ2U/OiBudW1iZXI7IGxpbWl0PzogbnVtYmVyfSxcbiAgb3B0aW9ucz86IE9taXQ8VXNlUXVlcnlPcHRpb25zPFdhbGxldEhpc3RvcnlSZXNwb25zZT4sICdxdWVyeUtleScgfCAncXVlcnlGbic+LFxuKTogVXNlUXVlcnlSZXN1bHQ8V2FsbGV0SGlzdG9yeVJlc3BvbnNlPiB7XG4gIHJldHVybiB1c2VRdWVyeSh7XG4gICAgcXVlcnlLZXk6IHdhbGxldEtleXMuc3BvdFJlZGVtcHRpb25zKHNwb3RJZCwgcGFyYW1zPy5wYWdlKSxcbiAgICBxdWVyeUZuOiBhc3luYyAoKTogUHJvbWlzZTxXYWxsZXRIaXN0b3J5UmVzcG9uc2U+ID0+IHtcbiAgICAgIGNvbnN0IGNsaWVudCA9IGdldEFwaUNsaWVudCgpXG4gICAgICBjb25zdCBxdWVyeVBhcmFtcyA9IG5ldyBVUkxTZWFyY2hQYXJhbXMoKVxuICAgICAgaWYgKHBhcmFtcz8ucGFnZSkgcXVlcnlQYXJhbXMuc2V0KCdwYWdlJywgU3RyaW5nKHBhcmFtcy5wYWdlKSlcbiAgICAgIGlmIChwYXJhbXM/LmxpbWl0KSBxdWVyeVBhcmFtcy5zZXQoJ2xpbWl0JywgU3RyaW5nKHBhcmFtcy5saW1pdCkpXG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGNsaWVudC5nZXQ8QXBpUmVzcG9uc2U8V2FsbGV0SGlzdG9yeVJlc3BvbnNlPj4oXG4gICAgICAgIGAvc3BvdHMvJHtzcG90SWR9L3JlZGVtcHRpb25zPyR7cXVlcnlQYXJhbXN9YCxcbiAgICAgIClcbiAgICAgIHJldHVybiBleHRyYWN0T2JqZWN0RGF0YTxXYWxsZXRIaXN0b3J5UmVzcG9uc2U+KHJlc3BvbnNlLmRhdGEuZGF0YSlcbiAgICB9LFxuICAgIGVuYWJsZWQ6ICEhc3BvdElkLFxuICAgIC4uLm9wdGlvbnMsXG4gIH0pXG59XG4iXX0=
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spotsdev/sdk",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Shared TypeScript SDK for Spots API - TanStack Query hooks, API client, and utilities",
5
5
  "main": "dist/index.js",
6
6
  "source": "src/index.ts",
@@ -32,7 +32,7 @@
32
32
  "react": ">=18.0.0"
33
33
  },
34
34
  "dependencies": {
35
- "@spotsdev/types": "^1.0.0"
35
+ "@spotsdev/types": "^1.1.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/node": "^20.0.0",
@@ -27,3 +27,6 @@ export * from './products'
27
27
 
28
28
  // Orders (marketplace)
29
29
  export * from './orders'
30
+
31
+ // Redemptions (wallet)
32
+ export * from './redemptions'
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Redemption Mutation Hooks
3
+ *
4
+ * TanStack Query mutations for redemption operations.
5
+ */
6
+
7
+ import {useMutation, useQueryClient, type UseMutationResult} from '@tanstack/react-query'
8
+ import {getApiClient} from '../client'
9
+ import {walletKeys, type WalletRedemption} from '../queries/wallet'
10
+
11
+ // ============================================================================
12
+ // TYPES
13
+ // ============================================================================
14
+
15
+ export interface RedeemRequest {
16
+ qrCode: string
17
+ spotId?: string
18
+ deviceInfo?: string
19
+ latitude?: number
20
+ longitude?: number
21
+ notes?: string
22
+ }
23
+
24
+ export interface VoidRedemptionRequest {
25
+ reason: string
26
+ }
27
+
28
+ // ============================================================================
29
+ // MUTATION HOOKS
30
+ // ============================================================================
31
+
32
+ /**
33
+ * Redeem a QR code (spot owner/staff action)
34
+ *
35
+ * @endpoint POST /redemptions/redeem
36
+ */
37
+ export function useRedeem(): UseMutationResult<WalletRedemption, Error, RedeemRequest> {
38
+ const queryClient = useQueryClient()
39
+
40
+ return useMutation({
41
+ mutationFn: async (request: RedeemRequest): Promise<WalletRedemption> => {
42
+ const client = getApiClient()
43
+ const response = await client.post('/redemptions/redeem', request)
44
+ return response.data.data
45
+ },
46
+ onSuccess: (_data, variables) => {
47
+ // Invalidate redemption lookup for this QR code
48
+ queryClient.invalidateQueries({
49
+ queryKey: walletKeys.lookup(variables.qrCode),
50
+ })
51
+ // Invalidate spot redemptions if spotId provided
52
+ if (variables.spotId) {
53
+ queryClient.invalidateQueries({
54
+ queryKey: walletKeys.spotRedemptions(variables.spotId),
55
+ })
56
+ }
57
+ },
58
+ })
59
+ }
60
+
61
+ /**
62
+ * Void a redemption (spot owner action)
63
+ *
64
+ * @endpoint PUT /redemptions/:id/void
65
+ */
66
+ export function useVoidRedemption(): UseMutationResult<
67
+ WalletRedemption,
68
+ Error,
69
+ {redemptionId: string; reason: string}
70
+ > {
71
+ const queryClient = useQueryClient()
72
+
73
+ return useMutation({
74
+ mutationFn: async ({
75
+ redemptionId,
76
+ reason,
77
+ }: {
78
+ redemptionId: string
79
+ reason: string
80
+ }): Promise<WalletRedemption> => {
81
+ const client = getApiClient()
82
+ const response = await client.put(`/redemptions/${redemptionId}/void`, {reason})
83
+ return response.data.data
84
+ },
85
+ onSuccess: () => {
86
+ // Invalidate wallet queries
87
+ queryClient.invalidateQueries({queryKey: walletKeys.all})
88
+ queryClient.invalidateQueries({queryKey: walletKeys.redemptions()})
89
+ },
90
+ })
91
+ }
@@ -46,3 +46,7 @@ export {productKeys} from './products'
46
46
  // Orders (marketplace)
47
47
  export * from './orders'
48
48
  export {orderKeys} from './orders'
49
+
50
+ // Wallet (redemptions)
51
+ export * from './wallet'
52
+ export {walletKeys} from './wallet'
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Wallet Query Hooks
3
+ *
4
+ * TanStack Query hooks for wallet and redemption operations.
5
+ */
6
+
7
+ import {
8
+ useQuery,
9
+ type UseQueryOptions,
10
+ type UseQueryResult,
11
+ } from '@tanstack/react-query'
12
+
13
+ import {getApiClient} from '../client'
14
+ import {type ApiResponse} from '../types'
15
+
16
+ // ============================================================================
17
+ // TYPES
18
+ // ============================================================================
19
+
20
+ export type RedemptionStatus = 'PENDING' | 'REDEEMED' | 'EXPIRED' | 'CANCELLED' | 'VOID'
21
+
22
+ export interface WalletProduct {
23
+ id: string
24
+ name: string
25
+ type: string
26
+ imageUrl: string | null
27
+ }
28
+
29
+ export interface WalletOrderItem {
30
+ product: WalletProduct
31
+ quantity: number
32
+ unitPrice: number
33
+ }
34
+
35
+ export interface WalletOrder {
36
+ id: string
37
+ orderNumber: string
38
+ spotId: string
39
+ createdAt: string
40
+ spot: {
41
+ id: string
42
+ name: string
43
+ slug: string
44
+ address: string | null
45
+ }
46
+ }
47
+
48
+ export interface WalletRedemption {
49
+ id: string
50
+ qrCode: string
51
+ qrCodeUrl: string | null
52
+ status: RedemptionStatus
53
+ validFrom: string
54
+ validUntil: string
55
+ redeemedAt: string | null
56
+ createdAt: string
57
+ orderItem: WalletOrderItem & {
58
+ order: WalletOrder
59
+ }
60
+ }
61
+
62
+ export interface RedemptionLookup extends WalletRedemption {
63
+ redeemedBy: {
64
+ id: string
65
+ name: string
66
+ } | null
67
+ spot: {
68
+ id: string
69
+ name: string
70
+ } | null
71
+ orderItem: WalletOrderItem & {
72
+ order: WalletOrder & {
73
+ user: {
74
+ id: string
75
+ name: string | null
76
+ avatarUrl: string | null
77
+ }
78
+ }
79
+ }
80
+ }
81
+
82
+ export interface WalletHistoryResponse {
83
+ data: WalletRedemption[]
84
+ meta: {
85
+ total: number
86
+ page: number
87
+ limit: number
88
+ totalPages: number
89
+ }
90
+ }
91
+
92
+ // ============================================================================
93
+ // HELPER FUNCTIONS
94
+ // ============================================================================
95
+
96
+ function extractArrayData<T>(data: unknown): T[] {
97
+ if (Array.isArray(data)) {
98
+ return data
99
+ }
100
+ if (data && typeof data === 'object' && 'data' in data) {
101
+ const nested = (data as {data: unknown}).data
102
+ if (Array.isArray(nested)) {
103
+ return nested
104
+ }
105
+ }
106
+ return []
107
+ }
108
+
109
+ function extractObjectData<T>(data: unknown): T {
110
+ if (
111
+ data &&
112
+ typeof data === 'object' &&
113
+ 'data' in data &&
114
+ !Array.isArray(data)
115
+ ) {
116
+ const nested = (data as {data: unknown}).data
117
+ if (
118
+ nested &&
119
+ typeof nested === 'object' &&
120
+ 'data' in nested &&
121
+ !Array.isArray(nested)
122
+ ) {
123
+ return (nested as {data: T}).data
124
+ }
125
+ return nested as T
126
+ }
127
+ return data as T
128
+ }
129
+
130
+ // ============================================================================
131
+ // QUERY KEYS
132
+ // ============================================================================
133
+
134
+ export const walletKeys = {
135
+ all: ['wallet'] as const,
136
+ active: () => [...walletKeys.all, 'active'] as const,
137
+ history: (page?: number) => [...walletKeys.all, 'history', page] as const,
138
+ redemptions: () => ['redemptions'] as const,
139
+ lookup: (qrCode: string) => [...walletKeys.redemptions(), 'lookup', qrCode] as const,
140
+ spotRedemptions: (spotId: string, page?: number) =>
141
+ [...walletKeys.redemptions(), 'spot', spotId, page] as const,
142
+ }
143
+
144
+ // ============================================================================
145
+ // QUERY HOOKS
146
+ // ============================================================================
147
+
148
+ /**
149
+ * Get user's active wallet items (pending redemptions)
150
+ *
151
+ * @endpoint GET /wallet
152
+ */
153
+ export function useWallet(
154
+ options?: Omit<UseQueryOptions<WalletRedemption[]>, 'queryKey' | 'queryFn'>,
155
+ ): UseQueryResult<WalletRedemption[]> {
156
+ return useQuery({
157
+ queryKey: walletKeys.active(),
158
+ queryFn: async (): Promise<WalletRedemption[]> => {
159
+ const client = getApiClient()
160
+ const response = await client.get<ApiResponse<unknown>>('/wallet')
161
+ return extractArrayData<WalletRedemption>(response.data.data)
162
+ },
163
+ ...options,
164
+ })
165
+ }
166
+
167
+ /**
168
+ * Get user's wallet history (all redemptions)
169
+ *
170
+ * @endpoint GET /wallet/history
171
+ */
172
+ export function useWalletHistory(
173
+ params?: {page?: number; limit?: number},
174
+ options?: Omit<UseQueryOptions<WalletHistoryResponse>, 'queryKey' | 'queryFn'>,
175
+ ): UseQueryResult<WalletHistoryResponse> {
176
+ return useQuery({
177
+ queryKey: walletKeys.history(params?.page),
178
+ queryFn: async (): Promise<WalletHistoryResponse> => {
179
+ const client = getApiClient()
180
+ const queryParams = new URLSearchParams()
181
+ if (params?.page) queryParams.set('page', String(params.page))
182
+ if (params?.limit) queryParams.set('limit', String(params.limit))
183
+ const response = await client.get<ApiResponse<WalletHistoryResponse>>(
184
+ `/wallet/history?${queryParams}`,
185
+ )
186
+ return extractObjectData<WalletHistoryResponse>(response.data.data)
187
+ },
188
+ ...options,
189
+ })
190
+ }
191
+
192
+ /**
193
+ * Lookup redemption by QR code (for scanner)
194
+ *
195
+ * @endpoint GET /redemptions/lookup/:qrCode
196
+ */
197
+ export function useRedemptionLookup(
198
+ qrCode: string,
199
+ options?: Omit<UseQueryOptions<RedemptionLookup>, 'queryKey' | 'queryFn'>,
200
+ ): UseQueryResult<RedemptionLookup> {
201
+ return useQuery({
202
+ queryKey: walletKeys.lookup(qrCode),
203
+ queryFn: async (): Promise<RedemptionLookup> => {
204
+ const client = getApiClient()
205
+ const response = await client.get<ApiResponse<unknown>>(
206
+ `/redemptions/lookup/${qrCode}`,
207
+ )
208
+ return extractObjectData<RedemptionLookup>(response.data.data)
209
+ },
210
+ enabled: !!qrCode && qrCode.length > 0,
211
+ ...options,
212
+ })
213
+ }
214
+
215
+ /**
216
+ * Get spot's redemption history (for spot owner)
217
+ *
218
+ * @endpoint GET /spots/:spotId/redemptions
219
+ */
220
+ export function useSpotRedemptions(
221
+ spotId: string,
222
+ params?: {page?: number; limit?: number},
223
+ options?: Omit<UseQueryOptions<WalletHistoryResponse>, 'queryKey' | 'queryFn'>,
224
+ ): UseQueryResult<WalletHistoryResponse> {
225
+ return useQuery({
226
+ queryKey: walletKeys.spotRedemptions(spotId, params?.page),
227
+ queryFn: async (): Promise<WalletHistoryResponse> => {
228
+ const client = getApiClient()
229
+ const queryParams = new URLSearchParams()
230
+ if (params?.page) queryParams.set('page', String(params.page))
231
+ if (params?.limit) queryParams.set('limit', String(params.limit))
232
+ const response = await client.get<ApiResponse<WalletHistoryResponse>>(
233
+ `/spots/${spotId}/redemptions?${queryParams}`,
234
+ )
235
+ return extractObjectData<WalletHistoryResponse>(response.data.data)
236
+ },
237
+ enabled: !!spotId,
238
+ ...options,
239
+ })
240
+ }