feat : Création de l'api, chargement des mockups

This commit is contained in:
Yaël Perret
2026-09-01 18:48:41 +02:00
parent fde710b607
commit 68d7ea3f9a
69 changed files with 1134 additions and 6 deletions

344
package-lock.json generated
View File

@@ -12,6 +12,8 @@
"@expo-google-fonts/jetbrains-mono": "^0.4.1", "@expo-google-fonts/jetbrains-mono": "^0.4.1",
"@expo-google-fonts/space-grotesk": "^0.4.1", "@expo-google-fonts/space-grotesk": "^0.4.1",
"@expo/ui": "~56.0.14", "@expo/ui": "~56.0.14",
"@tanstack/react-query": "^5.102.8",
"axios": "^1.20.0",
"babel-preset-expo": "^57.0.9", "babel-preset-expo": "^57.0.9",
"expo": "~56.0.5", "expo": "~56.0.5",
"expo-blur": "~56.0.4", "expo-blur": "~56.0.4",
@@ -45,7 +47,8 @@
"react-native-web": "~0.21.0", "react-native-web": "~0.21.0",
"react-native-worklets": "0.8.3", "react-native-worklets": "0.8.3",
"tailwindcss": "^3.4.19", "tailwindcss": "^3.4.19",
"zod": "^4.5.4" "zod": "^4.5.4",
"zustand": "^5.0.15"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "~19.2.2", "@types/react": "~19.2.2",
@@ -2869,6 +2872,32 @@
"integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@tanstack/query-core": {
"version": "5.102.8",
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.102.8.tgz",
"integrity": "sha512-ZNjkJ33CqvPNec/6lZBnHqLc3EVGPZ9ySLhYahU9TcuRFdmwXewuj0c4hwSWcGHqEUwcSrKeZ+oGcvPBqXcQcg==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
}
},
"node_modules/@tanstack/react-query": {
"version": "5.102.8",
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.102.8.tgz",
"integrity": "sha512-TYBea4OuXWD7MhaSHq069TWbFe7rcwWN6kzT7JF0OKi1K6c1gTv2IzD6A6ExJsCMozdkqBWeuIUZmu4KQg0O5A==",
"license": "MIT",
"dependencies": {
"@tanstack/query-core": "5.102.8"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
},
"peerDependencies": {
"react": "^18 || ^19"
}
},
"node_modules/@testing-library/dom": { "node_modules/@testing-library/dom": {
"version": "10.4.1", "version": "10.4.1",
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
@@ -3283,6 +3312,49 @@
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT"
},
"node_modules/axios": {
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz",
"integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.16.0",
"form-data": "^4.0.6",
"https-proxy-agent": "^5.0.1",
"proxy-from-env": "^2.1.0"
}
},
"node_modules/axios/node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
"license": "MIT",
"dependencies": {
"debug": "4"
},
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/axios/node_modules/https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
"license": "MIT",
"dependencies": {
"agent-base": "6",
"debug": "4"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/babel-plugin-polyfill-corejs2": { "node_modules/babel-plugin-polyfill-corejs2": {
"version": "0.4.17", "version": "0.4.17",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz",
@@ -3665,6 +3737,19 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/camelcase": { "node_modules/camelcase": {
"version": "6.3.0", "version": "6.3.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
@@ -3889,6 +3974,18 @@
"simple-swizzle": "^0.2.2" "simple-swizzle": "^0.2.2"
} }
}, },
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/commander": { "node_modules/commander": {
"version": "7.2.0", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
@@ -4174,6 +4271,15 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/depd": { "node_modules/depd": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@@ -4297,6 +4403,20 @@
"url": "https://github.com/fb55/domutils?sponsor=1" "url": "https://github.com/fb55/domutils?sponsor=1"
} }
}, },
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/ee-first": { "node_modules/ee-first": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -4345,6 +4465,15 @@
"stackframe": "^1.3.4" "stackframe": "^1.3.4"
} }
}, },
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": { "node_modules/es-errors": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
@@ -4354,6 +4483,33 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/es-object-atoms": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz",
"integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-set-tostringtag": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/escalade": { "node_modules/escalade": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
@@ -5613,12 +5769,69 @@
"integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/follow-redirects": {
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
"integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/fontfaceobserver": { "node_modules/fontfaceobserver": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.3.0.tgz", "resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.3.0.tgz",
"integrity": "sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==", "integrity": "sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==",
"license": "BSD-2-Clause" "license": "BSD-2-Clause"
}, },
"node_modules/form-data": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz",
"integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.4",
"mime-types": "^2.1.35"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/form-data/node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/form-data/node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/fresh": { "node_modules/fresh": {
"version": "0.5.2", "version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
@@ -5669,6 +5882,30 @@
"node": "6.* || 8.* || >= 10.*" "node": "6.* || 8.* || >= 10.*"
} }
}, },
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-nonce": { "node_modules/get-nonce": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
@@ -5678,6 +5915,19 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/getenv": { "node_modules/getenv": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/getenv/-/getenv-2.0.0.tgz", "resolved": "https://registry.npmjs.org/getenv/-/getenv-2.0.0.tgz",
@@ -5716,6 +5966,18 @@
"node": ">=10.13.0" "node": ">=10.13.0"
} }
}, },
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/graceful-fs": { "node_modules/graceful-fs": {
"version": "4.2.11", "version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
@@ -5731,10 +5993,37 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hasown": { "node_modules/hasown": {
"version": "2.0.3", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
"integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"function-bind": "^1.1.2" "function-bind": "^1.1.2"
@@ -6733,6 +7022,15 @@
"integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==",
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/mdn-data": { "node_modules/mdn-data": {
"version": "2.0.14", "version": "2.0.14",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
@@ -8088,6 +8386,15 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"node_modules/proxy-from-env": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
"integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==",
"license": "MIT",
"engines": {
"node": ">=10"
}
},
"node_modules/punycode": { "node_modules/punycode": {
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -10173,6 +10480,35 @@
"funding": { "funding": {
"url": "https://github.com/sponsors/colinhacks" "url": "https://github.com/sponsors/colinhacks"
} }
},
"node_modules/zustand": {
"version": "5.0.15",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.15.tgz",
"integrity": "sha512-MpSEjRiBkA9crSYeOUH32rJC7SVqAbm0Fqcqge/bUi2PPoLcBWKOsG+C8mevmpr8TwXHBVkChbbJiyvkE+i/3A==",
"license": "MIT",
"engines": {
"node": ">=12.20.0"
},
"peerDependencies": {
"@types/react": ">=18.0.0",
"immer": ">=9.0.6",
"react": ">=18.0.0",
"use-sync-external-store": ">=1.2.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"immer": {
"optional": true
},
"react": {
"optional": true
},
"use-sync-external-store": {
"optional": true
}
}
} }
} }
} }

View File

@@ -7,6 +7,8 @@
"@expo-google-fonts/jetbrains-mono": "^0.4.1", "@expo-google-fonts/jetbrains-mono": "^0.4.1",
"@expo-google-fonts/space-grotesk": "^0.4.1", "@expo-google-fonts/space-grotesk": "^0.4.1",
"@expo/ui": "~56.0.14", "@expo/ui": "~56.0.14",
"@tanstack/react-query": "^5.102.8",
"axios": "^1.20.0",
"babel-preset-expo": "^57.0.9", "babel-preset-expo": "^57.0.9",
"expo": "~56.0.5", "expo": "~56.0.5",
"expo-blur": "~56.0.4", "expo-blur": "~56.0.4",
@@ -40,7 +42,8 @@
"react-native-web": "~0.21.0", "react-native-web": "~0.21.0",
"react-native-worklets": "0.8.3", "react-native-worklets": "0.8.3",
"tailwindcss": "^3.4.19", "tailwindcss": "^3.4.19",
"zod": "^4.5.4" "zod": "^4.5.4",
"zustand": "^5.0.15"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "~19.2.2", "@types/react": "~19.2.2",

11
src/api/client.ts Normal file
View File

@@ -0,0 +1,11 @@
import axios from 'axios';
import { API_BASE_URL } from './config';
export const apiClient = axios.create({
baseURL: API_BASE_URL,
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});

4
src/api/config.ts Normal file
View File

@@ -0,0 +1,4 @@
export const API_BASE_URL = process.env.EXPO_PUBLIC_API_BASE_URL ?? 'http://localhost:3000';
// Toggle once here to switch all API functions between mocks and real backend.
export const API_USE_MOCKS = (process.env.EXPO_PUBLIC_API_USE_MOCKS ?? 'true') === 'true';

View File

@@ -0,0 +1,9 @@
import type { Animator } from '@/models';
import { mockAnimators } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const animatorsApi = createResourceApi<Animator>({
endpoint: 'animators',
mockData: mockAnimators,
resolveMockKey: (item) => item.id,
});

View File

@@ -0,0 +1,9 @@
import { mockCommentLikes } from '@/mocks';
import type { CommentLike } from '@/models';
import { createResourceApi } from '../resourceFactory';
export const comment_likesApi = createResourceApi<CommentLike>({
endpoint: 'comment_likes',
mockData: mockCommentLikes,
resolveMockKey: (item) => `${item.user_id}:${item.comment_id}`,
});

View File

@@ -0,0 +1,9 @@
import type { Comment } from '@/models';
import { mockComments } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const commentsApi = createResourceApi<Comment>({
endpoint: 'comments',
mockData: mockComments,
resolveMockKey: (item) => item.id,
});

View File

@@ -0,0 +1,9 @@
import type { EventExternalLink } from '@/models';
import { mockEventExternalLinks } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const event_external_linksApi = createResourceApi<EventExternalLink>({
endpoint: 'event_external_links',
mockData: mockEventExternalLinks,
resolveMockKey: (item) => item.id,
});

View File

@@ -0,0 +1,9 @@
import { mockEventHashtags } from '@/mocks';
import type { EventHashtag } from '@/models';
import { createResourceApi } from '../resourceFactory';
export const event_hashtagsApi = createResourceApi<EventHashtag>({
endpoint: 'event_hashtags',
mockData: mockEventHashtags,
resolveMockKey: (item) => `${item.event_id}:${item.hashtag_id}`,
});

View File

@@ -0,0 +1,9 @@
import type { EventImage } from '@/models';
import { mockEventImages } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const event_imagesApi = createResourceApi<EventImage>({
endpoint: 'event_images',
mockData: mockEventImages,
resolveMockKey: (item) => item.id,
});

View File

@@ -0,0 +1,9 @@
import type { EventLineup } from '@/models';
import { mockEventLineup } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const event_lineupApi = createResourceApi<EventLineup>({
endpoint: 'event_lineup',
mockData: mockEventLineup,
resolveMockKey: (item) => item.id,
});

View File

@@ -0,0 +1,9 @@
import type { EventStatsSnapshot } from '@/models';
import { mockEventStatsSnapshots } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const event_stats_snapshotsApi = createResourceApi<EventStatsSnapshot>({
endpoint: 'event_stats_snapshots',
mockData: mockEventStatsSnapshots,
resolveMockKey: (item) => item.id,
});

View File

@@ -0,0 +1,9 @@
import { mockEventThemes } from '@/mocks';
import type { EventTheme } from '@/models';
import { createResourceApi } from '../resourceFactory';
export const event_themesApi = createResourceApi<EventTheme>({
endpoint: 'event_themes',
mockData: mockEventThemes,
resolveMockKey: (item) => `${item.event_id}:${item.theme_id}`,
});

View File

@@ -0,0 +1,9 @@
import type { Event } from '@/models';
import { mockEvents } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const eventsApi = createResourceApi<Event>({
endpoint: 'events',
mockData: mockEvents,
resolveMockKey: (item) => item.id,
});

View File

@@ -0,0 +1,9 @@
import type { Hashtag } from '@/models';
import { mockHashtags } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const hashtagsApi = createResourceApi<Hashtag>({
endpoint: 'hashtags',
mockData: mockHashtags,
resolveMockKey: (item) => item.id,
});

29
src/api/entities/index.ts Normal file
View File

@@ -0,0 +1,29 @@
export * from './animators';
export * from './comment_likes';
export * from './comments';
export * from './event_external_links';
export * from './event_hashtags';
export * from './event_images';
export * from './event_lineup';
export * from './event_stats_snapshots';
export * from './event_themes';
export * from './events';
export * from './hashtags';
export * from './organizer_members';
export * from './organizer_subscriptions';
export * from './organizers';
export * from './plans';
export * from './post_likes';
export * from './post_media';
export * from './posts';
export * from './search_history';
export * from './social_auth_providers';
export * from './themes';
export * from './tickets';
export * from './user_animator_follows';
export * from './user_event_interactions';
export * from './user_event_shares';
export * from './user_organizer_follows';
export * from './user_theme_preferences';
export * from './users';

View File

@@ -0,0 +1,9 @@
import type { OrganizerMember } from '@/models';
import { mockOrganizerMembers } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const organizer_membersApi = createResourceApi<OrganizerMember>({
endpoint: 'organizer_members',
mockData: mockOrganizerMembers,
resolveMockKey: (item) => item.id,
});

View File

@@ -0,0 +1,9 @@
import type { OrganizerSubscription } from '@/models';
import { mockOrganizerSubscriptions } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const organizer_subscriptionsApi = createResourceApi<OrganizerSubscription>({
endpoint: 'organizer_subscriptions',
mockData: mockOrganizerSubscriptions,
resolveMockKey: (item) => item.id,
});

View File

@@ -0,0 +1,9 @@
import type { Organizer } from '@/models';
import { mockOrganizers } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const organizersApi = createResourceApi<Organizer>({
endpoint: 'organizers',
mockData: mockOrganizers,
resolveMockKey: (item) => item.id,
});

View File

@@ -0,0 +1,9 @@
import type { Plan } from '@/models';
import { mockPlans } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const plansApi = createResourceApi<Plan>({
endpoint: 'plans',
mockData: mockPlans,
resolveMockKey: (item) => item.id,
});

View File

@@ -0,0 +1,9 @@
import { mockPostLikes } from '@/mocks';
import type { PostLike } from '@/models';
import { createResourceApi } from '../resourceFactory';
export const post_likesApi = createResourceApi<PostLike>({
endpoint: 'post_likes',
mockData: mockPostLikes,
resolveMockKey: (item) => `${item.user_id}:${item.post_id}`,
});

View File

@@ -0,0 +1,9 @@
import type { PostMedia } from '@/models';
import { mockPostMedia } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const post_mediaApi = createResourceApi<PostMedia>({
endpoint: 'post_media',
mockData: mockPostMedia,
resolveMockKey: (item) => item.id,
});

View File

@@ -0,0 +1,9 @@
import type { Post } from '@/models';
import { mockPosts } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const postsApi = createResourceApi<Post>({
endpoint: 'posts',
mockData: mockPosts,
resolveMockKey: (item) => item.id,
});

View File

@@ -0,0 +1,9 @@
import type { SearchHistory } from '@/models';
import { mockSearchHistory } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const search_historyApi = createResourceApi<SearchHistory>({
endpoint: 'search_history',
mockData: mockSearchHistory,
resolveMockKey: (item) => item.id,
});

View File

@@ -0,0 +1,9 @@
import type { SocialAuthProvider } from '@/models';
import { mockSocialAuthProviders } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const social_auth_providersApi = createResourceApi<SocialAuthProvider>({
endpoint: 'social_auth_providers',
mockData: mockSocialAuthProviders,
resolveMockKey: (item) => item.id,
});

View File

@@ -0,0 +1,9 @@
import type { Theme } from '@/models';
import { mockThemes } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const themesApi = createResourceApi<Theme>({
endpoint: 'themes',
mockData: mockThemes,
resolveMockKey: (item) => item.id,
});

View File

@@ -0,0 +1,9 @@
import type { Ticket } from '@/models';
import { mockTickets } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const ticketsApi = createResourceApi<Ticket>({
endpoint: 'tickets',
mockData: mockTickets,
resolveMockKey: (item) => item.id,
});

View File

@@ -0,0 +1,9 @@
import { mockUserAnimatorFollows } from '@/mocks';
import type { UserAnimatorFollow } from '@/models';
import { createResourceApi } from '../resourceFactory';
export const user_animator_followsApi = createResourceApi<UserAnimatorFollow>({
endpoint: 'user_animator_follows',
mockData: mockUserAnimatorFollows,
resolveMockKey: (item) => `${item.user_id}:${item.animator_id}`,
});

View File

@@ -0,0 +1,9 @@
import { mockUserEventInteractions } from '@/mocks';
import type { UserEventInteraction } from '@/models';
import { createResourceApi } from '../resourceFactory';
export const user_event_interactionsApi = createResourceApi<UserEventInteraction>({
endpoint: 'user_event_interactions',
mockData: mockUserEventInteractions,
resolveMockKey: (item) => `${item.user_id}:${item.event_id}`,
});

View File

@@ -0,0 +1,9 @@
import type { UserEventShare } from '@/models';
import { mockUserEventShares } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const user_event_sharesApi = createResourceApi<UserEventShare>({
endpoint: 'user_event_shares',
mockData: mockUserEventShares,
resolveMockKey: (item) => item.id,
});

View File

@@ -0,0 +1,9 @@
import { mockUserOrganizerFollows } from '@/mocks';
import type { UserOrganizerFollow } from '@/models';
import { createResourceApi } from '../resourceFactory';
export const user_organizer_followsApi = createResourceApi<UserOrganizerFollow>({
endpoint: 'user_organizer_follows',
mockData: mockUserOrganizerFollows,
resolveMockKey: (item) => `${item.user_id}:${item.organizer_id}`,
});

View File

@@ -0,0 +1,9 @@
import { mockUserThemePreferences } from '@/mocks';
import type { UserThemePreference } from '@/models';
import { createResourceApi } from '../resourceFactory';
export const user_theme_preferencesApi = createResourceApi<UserThemePreference>({
endpoint: 'user_theme_preferences',
mockData: mockUserThemePreferences,
resolveMockKey: (item) => `${item.user_id}:${item.theme_id}`,
});

View File

@@ -0,0 +1,9 @@
import type { User } from '@/models';
import { mockUsers } from '@/mocks';
import { createResourceApi } from '../resourceFactory';
export const usersApi = createResourceApi<User>({
endpoint: 'users',
mockData: mockUsers,
resolveMockKey: (item) => item.id,
});

33
src/api/index.ts Normal file
View File

@@ -0,0 +1,33 @@
export * from './client';
export * from './config';
export * from './resourceFactory';
export * from './types';
export * from './entities/animators';
export * from './entities/comment_likes';
export * from './entities/comments';
export * from './entities/event_external_links';
export * from './entities/event_hashtags';
export * from './entities/event_images';
export * from './entities/event_lineup';
export * from './entities/event_stats_snapshots';
export * from './entities/event_themes';
export * from './entities/events';
export * from './entities/hashtags';
export * from './entities/organizer_members';
export * from './entities/organizer_subscriptions';
export * from './entities/organizers';
export * from './entities/plans';
export * from './entities/post_likes';
export * from './entities/post_media';
export * from './entities/posts';
export * from './entities/search_history';
export * from './entities/social_auth_providers';
export * from './entities/themes';
export * from './entities/tickets';
export * from './entities/user_animator_follows';
export * from './entities/user_event_interactions';
export * from './entities/user_event_shares';
export * from './entities/user_organizer_follows';
export * from './entities/user_theme_preferences';
export * from './entities/users';

90
src/api/mockStore.ts Normal file
View File

@@ -0,0 +1,90 @@
type KeyResolver<T> = (item: T) => string;
type MockStoreOptions<T> = {
data: T[];
resolveKey: KeyResolver<T>;
};
const clone = <T>(value: T): T => {
if (typeof globalThis.structuredClone === 'function') {
return globalThis.structuredClone(value);
}
return JSON.parse(JSON.stringify(value)) as T;
};
const createMockId = (): string => {
const random = Math.random().toString(16).slice(2, 10).padEnd(8, '0');
return `00000000-0000-4000-8000-${random}`;
};
const ensureHasId = <T>(payload: Partial<T>): Partial<T> => {
if ('id' in payload && typeof payload.id === 'string' && payload.id.length > 0) {
return payload;
}
return {
...payload,
id: createMockId(),
};
};
export const createMockStore = <T>(options: MockStoreOptions<T>) => {
const { resolveKey } = options;
const records = [...options.data];
const findIndex = (id: string): number => records.findIndex((item) => resolveKey(item) === id);
return {
list: async (): Promise<T[]> => clone(records),
get: async (id: string): Promise<T> => {
const index = findIndex(id);
if (index === -1) {
throw new Error(`Mock record not found for id "${id}"`);
}
return clone(records[index]);
},
create: async (payload: Partial<T>): Promise<T> => {
const next = ensureHasId(payload) as T;
records.push(next);
return clone(next);
},
update: async (id: string, payload: Partial<T>): Promise<T> => {
const index = findIndex(id);
if (index === -1) {
throw new Error(`Mock record not found for id "${id}"`);
}
const next = {
...records[index],
...payload,
};
records[index] = next;
return clone(next);
},
patch: async (id: string, payload: Partial<T>): Promise<T> => {
const index = findIndex(id);
if (index === -1) {
throw new Error(`Mock record not found for id "${id}"`);
}
const next = {
...records[index],
...payload,
};
records[index] = next;
return clone(next);
},
remove: async (id: string): Promise<void> => {
const index = findIndex(id);
if (index === -1) {
throw new Error(`Mock record not found for id "${id}"`);
}
records.splice(index, 1);
},
};
};

View File

@@ -0,0 +1,66 @@
import type { AxiosInstance } from 'axios';
import { apiClient } from './client';
import { API_USE_MOCKS } from './config';
import { createMockStore } from './mockStore';
import type { CreatePayload, CrudApi, UpdatePayload } from './types';
type CreateResourceApiOptions<T> = {
endpoint: string;
mockData: T[];
resolveMockKey: (item: T) => string;
client?: AxiosInstance;
useMocks?: boolean;
};
export const createResourceApi = <T>(options: CreateResourceApiOptions<T>): CrudApi<T> => {
const {
endpoint,
mockData,
resolveMockKey,
client = apiClient,
useMocks = API_USE_MOCKS,
} = options;
const mockStore = createMockStore<T>({
data: mockData,
resolveKey: resolveMockKey,
});
if (useMocks) {
return {
list: () => mockStore.list(),
get: (id) => mockStore.get(id),
create: (payload) => mockStore.create(payload),
update: (id, payload) => mockStore.update(id, payload),
patch: (id, payload) => mockStore.patch(id, payload),
remove: (id) => mockStore.remove(id),
};
}
return {
list: async () => {
const response = await client.get<T[]>(`/${endpoint}`);
return response.data;
},
get: async (id: string) => {
const response = await client.get<T>(`/${endpoint}/${id}`);
return response.data;
},
create: async (payload: CreatePayload<T>) => {
const response = await client.post<T>(`/${endpoint}`, payload);
return response.data;
},
update: async (id: string, payload: UpdatePayload<T>) => {
const response = await client.put<T>(`/${endpoint}/${id}`, payload);
return response.data;
},
patch: async (id: string, payload: UpdatePayload<T>) => {
const response = await client.patch<T>(`/${endpoint}/${id}`, payload);
return response.data;
},
remove: async (id: string) => {
await client.delete(`/${endpoint}/${id}`);
},
};
};

13
src/api/types.ts Normal file
View File

@@ -0,0 +1,13 @@
export type EntityWithId = { id: string };
export type CreatePayload<T> = Partial<T>;
export type UpdatePayload<T> = Partial<T>;
export type CrudApi<T> = {
list: () => Promise<T[]>;
get: (id: string) => Promise<T>;
create: (payload: CreatePayload<T>) => Promise<T>;
update: (id: string, payload: UpdatePayload<T>) => Promise<T>;
patch: (id: string, payload: UpdatePayload<T>) => Promise<T>;
remove: (id: string) => Promise<void>;
};

View File

@@ -1,5 +1,7 @@
import { QueryClientProvider } from '@tanstack/react-query';
import { Stack } from 'expo-router'; import { Stack } from 'expo-router';
import { queryClient } from '../hooks/queryClient';
import { useAppFonts } from '../theme/typography'; import { useAppFonts } from '../theme/typography';
export default function RootLayout() { export default function RootLayout() {
@@ -10,6 +12,8 @@ export default function RootLayout() {
} }
return ( return (
<QueryClientProvider client={queryClient}>
<Stack /> <Stack />
</QueryClientProvider>
); );
} }

View File

@@ -0,0 +1,5 @@
import type { Animator } from '@/models';
import { animatorsApi } from '@/api/entities/animators';
import { createCrudHooks } from './createCrudHooks';
export const animatorsHooks = createCrudHooks<Animator>('animators', animatorsApi);

View File

@@ -0,0 +1,5 @@
import type { CommentLike } from '@/models';
import { comment_likesApi } from '@/api/entities/comment_likes';
import { createCrudHooks } from './createCrudHooks';
export const comment_likesHooks = createCrudHooks<CommentLike>('comment_likes', comment_likesApi);

View File

@@ -0,0 +1,5 @@
import type { Comment } from '@/models';
import { commentsApi } from '@/api/entities/comments';
import { createCrudHooks } from './createCrudHooks';
export const commentsHooks = createCrudHooks<Comment>('comments', commentsApi);

View File

@@ -0,0 +1,102 @@
import type { CrudApi } from '@/api/types';
import {
useMutation,
useQuery,
useQueryClient,
type UseMutationOptions,
type UseQueryOptions,
} from '@tanstack/react-query';
type ResourceId = string;
type ListKey = [string, 'list'];
type DetailKey = [string, 'detail', ResourceId];
export const createCrudHooks = <T>(resourceKey: string, api: CrudApi<T>) => {
const listKey: ListKey = [resourceKey, 'list'];
const useListQuery = (options?: Omit<UseQueryOptions<T[], Error, T[], ListKey>, 'queryKey' | 'queryFn'>) =>
useQuery({
queryKey: listKey,
queryFn: () => api.list(),
...options,
});
const useDetailQuery = (
id: ResourceId,
options?: Omit<UseQueryOptions<T, Error, T, DetailKey>, 'queryKey' | 'queryFn'>,
) =>
useQuery({
queryKey: [resourceKey, 'detail', id],
queryFn: () => api.get(id),
enabled: id !== undefined && id !== null && (options?.enabled ?? true),
...options,
});
const useCreateMutation = (
options?: UseMutationOptions<T, Error, Partial<T>>,
) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data) => api.create(data),
...options,
onSuccess: (data, variables, onMutateResult, context) => {
queryClient.invalidateQueries({ queryKey: listKey });
options?.onSuccess?.(data, variables, onMutateResult, context);
},
});
};
const useUpdateMutation = (
options?: UseMutationOptions<T, Error, { id: ResourceId; data: Partial<T> }>,
) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, data }) => api.update(id, data),
...options,
onSuccess: (data, variables, onMutateResult, context) => {
queryClient.invalidateQueries({ queryKey: listKey });
queryClient.invalidateQueries({ queryKey: [resourceKey, 'detail', variables.id] });
options?.onSuccess?.(data, variables, onMutateResult, context);
},
});
};
const usePatchMutation = (
options?: UseMutationOptions<T, Error, { id: ResourceId; data: Partial<T> }>,
) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, data }) => api.patch(id, data),
...options,
onSuccess: (data, variables, onMutateResult, context) => {
queryClient.invalidateQueries({ queryKey: listKey });
queryClient.invalidateQueries({ queryKey: [resourceKey, 'detail', variables.id] });
options?.onSuccess?.(data, variables, onMutateResult, context);
},
});
};
const useDeleteMutation = (
options?: UseMutationOptions<void, Error, ResourceId>,
) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id) => api.remove(id),
...options,
onSuccess: (data, variables, onMutateResult, context) => {
queryClient.invalidateQueries({ queryKey: listKey });
queryClient.invalidateQueries({ queryKey: [resourceKey, 'detail', variables] });
options?.onSuccess?.(data, variables, onMutateResult, context);
},
});
};
return {
useListQuery,
useDetailQuery,
useCreateMutation,
useUpdateMutation,
usePatchMutation,
useDeleteMutation,
};
};

View File

@@ -0,0 +1,5 @@
import type { EventExternalLink } from '@/models';
import { event_external_linksApi } from '@/api/entities/event_external_links';
import { createCrudHooks } from './createCrudHooks';
export const event_external_linksHooks = createCrudHooks<EventExternalLink>('event_external_links', event_external_linksApi);

View File

@@ -0,0 +1,5 @@
import type { EventHashtag } from '@/models';
import { event_hashtagsApi } from '@/api/entities/event_hashtags';
import { createCrudHooks } from './createCrudHooks';
export const event_hashtagsHooks = createCrudHooks<EventHashtag>('event_hashtags', event_hashtagsApi);

View File

@@ -0,0 +1,5 @@
import type { EventImage } from '@/models';
import { event_imagesApi } from '@/api/entities/event_images';
import { createCrudHooks } from './createCrudHooks';
export const event_imagesHooks = createCrudHooks<EventImage>('event_images', event_imagesApi);

View File

@@ -0,0 +1,5 @@
import type { EventLineup } from '@/models';
import { event_lineupApi } from '@/api/entities/event_lineup';
import { createCrudHooks } from './createCrudHooks';
export const event_lineupHooks = createCrudHooks<EventLineup>('event_lineup', event_lineupApi);

View File

@@ -0,0 +1,5 @@
import type { EventStatsSnapshot } from '@/models';
import { event_stats_snapshotsApi } from '@/api/entities/event_stats_snapshots';
import { createCrudHooks } from './createCrudHooks';
export const event_stats_snapshotsHooks = createCrudHooks<EventStatsSnapshot>('event_stats_snapshots', event_stats_snapshotsApi);

View File

@@ -0,0 +1,5 @@
import type { EventTheme } from '@/models';
import { event_themesApi } from '@/api/entities/event_themes';
import { createCrudHooks } from './createCrudHooks';
export const event_themesHooks = createCrudHooks<EventTheme>('event_themes', event_themesApi);

5
src/hooks/api/events.ts Normal file
View File

@@ -0,0 +1,5 @@
import type { Event } from '@/models';
import { eventsApi } from '@/api/entities/events';
import { createCrudHooks } from './createCrudHooks';
export const eventsHooks = createCrudHooks<Event>('events', eventsApi);

View File

@@ -0,0 +1,5 @@
import type { Hashtag } from '@/models';
import { hashtagsApi } from '@/api/entities/hashtags';
import { createCrudHooks } from './createCrudHooks';
export const hashtagsHooks = createCrudHooks<Hashtag>('hashtags', hashtagsApi);

30
src/hooks/api/index.ts Normal file
View File

@@ -0,0 +1,30 @@
export * from './createCrudHooks';
export * from './animators';
export * from './comment_likes';
export * from './comments';
export * from './event_external_links';
export * from './event_hashtags';
export * from './event_images';
export * from './event_lineup';
export * from './event_stats_snapshots';
export * from './event_themes';
export * from './events';
export * from './hashtags';
export * from './organizer_members';
export * from './organizer_subscriptions';
export * from './organizers';
export * from './plans';
export * from './post_likes';
export * from './post_media';
export * from './posts';
export * from './search_history';
export * from './social_auth_providers';
export * from './themes';
export * from './tickets';
export * from './user_animator_follows';
export * from './user_event_interactions';
export * from './user_event_shares';
export * from './user_organizer_follows';
export * from './user_theme_preferences';
export * from './users';

View File

@@ -0,0 +1,5 @@
import type { OrganizerMember } from '@/models';
import { organizer_membersApi } from '@/api/entities/organizer_members';
import { createCrudHooks } from './createCrudHooks';
export const organizer_membersHooks = createCrudHooks<OrganizerMember>('organizer_members', organizer_membersApi);

View File

@@ -0,0 +1,5 @@
import type { OrganizerSubscription } from '@/models';
import { organizer_subscriptionsApi } from '@/api/entities/organizer_subscriptions';
import { createCrudHooks } from './createCrudHooks';
export const organizer_subscriptionsHooks = createCrudHooks<OrganizerSubscription>('organizer_subscriptions', organizer_subscriptionsApi);

View File

@@ -0,0 +1,5 @@
import type { Organizer } from '@/models';
import { organizersApi } from '@/api/entities/organizers';
import { createCrudHooks } from './createCrudHooks';
export const organizersHooks = createCrudHooks<Organizer>('organizers', organizersApi);

5
src/hooks/api/plans.ts Normal file
View File

@@ -0,0 +1,5 @@
import type { Plan } from '@/models';
import { plansApi } from '@/api/entities/plans';
import { createCrudHooks } from './createCrudHooks';
export const plansHooks = createCrudHooks<Plan>('plans', plansApi);

View File

@@ -0,0 +1,5 @@
import type { PostLike } from '@/models';
import { post_likesApi } from '@/api/entities/post_likes';
import { createCrudHooks } from './createCrudHooks';
export const post_likesHooks = createCrudHooks<PostLike>('post_likes', post_likesApi);

View File

@@ -0,0 +1,5 @@
import type { PostMedia } from '@/models';
import { post_mediaApi } from '@/api/entities/post_media';
import { createCrudHooks } from './createCrudHooks';
export const post_mediaHooks = createCrudHooks<PostMedia>('post_media', post_mediaApi);

5
src/hooks/api/posts.ts Normal file
View File

@@ -0,0 +1,5 @@
import type { Post } from '@/models';
import { postsApi } from '@/api/entities/posts';
import { createCrudHooks } from './createCrudHooks';
export const postsHooks = createCrudHooks<Post>('posts', postsApi);

View File

@@ -0,0 +1,5 @@
import type { SearchHistory } from '@/models';
import { search_historyApi } from '@/api/entities/search_history';
import { createCrudHooks } from './createCrudHooks';
export const search_historyHooks = createCrudHooks<SearchHistory>('search_history', search_historyApi);

View File

@@ -0,0 +1,5 @@
import type { SocialAuthProvider } from '@/models';
import { social_auth_providersApi } from '@/api/entities/social_auth_providers';
import { createCrudHooks } from './createCrudHooks';
export const social_auth_providersHooks = createCrudHooks<SocialAuthProvider>('social_auth_providers', social_auth_providersApi);

5
src/hooks/api/themes.ts Normal file
View File

@@ -0,0 +1,5 @@
import type { Theme } from '@/models';
import { themesApi } from '@/api/entities/themes';
import { createCrudHooks } from './createCrudHooks';
export const themesHooks = createCrudHooks<Theme>('themes', themesApi);

5
src/hooks/api/tickets.ts Normal file
View File

@@ -0,0 +1,5 @@
import type { Ticket } from '@/models';
import { ticketsApi } from '@/api/entities/tickets';
import { createCrudHooks } from './createCrudHooks';
export const ticketsHooks = createCrudHooks<Ticket>('tickets', ticketsApi);

View File

@@ -0,0 +1,5 @@
import type { UserAnimatorFollow } from '@/models';
import { user_animator_followsApi } from '@/api/entities/user_animator_follows';
import { createCrudHooks } from './createCrudHooks';
export const user_animator_followsHooks = createCrudHooks<UserAnimatorFollow>('user_animator_follows', user_animator_followsApi);

View File

@@ -0,0 +1,5 @@
import type { UserEventInteraction } from '@/models';
import { user_event_interactionsApi } from '@/api/entities/user_event_interactions';
import { createCrudHooks } from './createCrudHooks';
export const user_event_interactionsHooks = createCrudHooks<UserEventInteraction>('user_event_interactions', user_event_interactionsApi);

View File

@@ -0,0 +1,5 @@
import type { UserEventShare } from '@/models';
import { user_event_sharesApi } from '@/api/entities/user_event_shares';
import { createCrudHooks } from './createCrudHooks';
export const user_event_sharesHooks = createCrudHooks<UserEventShare>('user_event_shares', user_event_sharesApi);

View File

@@ -0,0 +1,5 @@
import type { UserOrganizerFollow } from '@/models';
import { user_organizer_followsApi } from '@/api/entities/user_organizer_follows';
import { createCrudHooks } from './createCrudHooks';
export const user_organizer_followsHooks = createCrudHooks<UserOrganizerFollow>('user_organizer_follows', user_organizer_followsApi);

View File

@@ -0,0 +1,5 @@
import type { UserThemePreference } from '@/models';
import { user_theme_preferencesApi } from '@/api/entities/user_theme_preferences';
import { createCrudHooks } from './createCrudHooks';
export const user_theme_preferencesHooks = createCrudHooks<UserThemePreference>('user_theme_preferences', user_theme_preferencesApi);

5
src/hooks/api/users.ts Normal file
View File

@@ -0,0 +1,5 @@
import type { User } from '@/models';
import { usersApi } from '@/api/entities/users';
import { createCrudHooks } from './createCrudHooks';
export const usersHooks = createCrudHooks<User>('users', usersApi);

15
src/hooks/queryClient.ts Normal file
View File

@@ -0,0 +1,15 @@
import { QueryClient } from '@tanstack/react-query';
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 30_000,
gcTime: 5 * 60_000,
refetchOnWindowFocus: false,
retry: 1,
},
mutations: {
retry: 0,
},
},
});