2026-04-06
This commit is contained in:
parent
2971f5516d
commit
7baeb28fc1
36 changed files with 390 additions and 415 deletions
|
|
@ -2,7 +2,9 @@
|
||||||
"language_servers": [
|
"language_servers": [
|
||||||
"!biome",
|
"!biome",
|
||||||
"!deno",
|
"!deno",
|
||||||
|
"!eslint",
|
||||||
"!intelephense",
|
"!intelephense",
|
||||||
|
"!oxfmt",
|
||||||
"!prettier",
|
"!prettier",
|
||||||
"!tailwindcss-language-server",
|
"!tailwindcss-language-server",
|
||||||
"!vtsls",
|
"!vtsls",
|
||||||
|
|
|
||||||
22
bun.lock
22
bun.lock
|
|
@ -17,7 +17,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@effect/language-service": "^0.84.3",
|
"@effect/language-service": "^0.84.3",
|
||||||
"@gcch/configuration-eslint": "git+https://git.gcch.fr/gcch/configuration-eslint#62ee424274",
|
"@gcch/configuration-eslint": "git+https://git.gcch.fr/gcch/configuration-eslint#62ee424274",
|
||||||
"@gcch/configuration-oxlint": "git+https://git.gcch.fr/gcch/configuration-oxlint#3e49f5e2fb",
|
"@gcch/configuration-oxlint": "git+https://git.gcch.fr/gcch/configuration-oxlint#bedd1fa23aff",
|
||||||
"@gcch/configuration-prettier": "git+https://git.gcch.fr/gcch/configuration-prettier#8de937e801",
|
"@gcch/configuration-prettier": "git+https://git.gcch.fr/gcch/configuration-prettier#8de937e801",
|
||||||
"@playwright/test": "^1.59.1",
|
"@playwright/test": "^1.59.1",
|
||||||
"@sentry/core": "^10.47.0",
|
"@sentry/core": "^10.47.0",
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
"@vitejs/plugin-legacy": "^8.0.1",
|
"@vitejs/plugin-legacy": "^8.0.1",
|
||||||
"better-typescript-lib": "^2.12.0",
|
"better-typescript-lib": "^2.12.0",
|
||||||
"browserslist": "^4.28.2",
|
"browserslist": "^4.28.2",
|
||||||
"caniuse-lite": "^1.0.30001785",
|
"caniuse-lite": "^1.0.30001786",
|
||||||
"eslint": "^10.2.0",
|
"eslint": "^10.2.0",
|
||||||
"eslint-plugin-functional": "^9.0.4",
|
"eslint-plugin-functional": "^9.0.4",
|
||||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||||
|
|
@ -44,7 +44,7 @@
|
||||||
"playwright": "^1.59.1",
|
"playwright": "^1.59.1",
|
||||||
"prettier": "^3.8.1",
|
"prettier": "^3.8.1",
|
||||||
"prettier-plugin-pkg": "^0.22.1",
|
"prettier-plugin-pkg": "^0.22.1",
|
||||||
"prettier-plugin-sh": "^0.18.0",
|
"prettier-plugin-sh": "^0.18.1",
|
||||||
"sass-embedded": "^1.99.0",
|
"sass-embedded": "^1.99.0",
|
||||||
"stylelint": "^17.6.0",
|
"stylelint": "^17.6.0",
|
||||||
"stylelint-config-clean-order": "^8.0.1",
|
"stylelint-config-clean-order": "^8.0.1",
|
||||||
|
|
@ -54,7 +54,7 @@
|
||||||
"stylelint-plugin-logical-css": "^2.1.0",
|
"stylelint-plugin-logical-css": "^2.1.0",
|
||||||
"typescript": "6.0.2",
|
"typescript": "6.0.2",
|
||||||
"typescript-eslint": "^8.58.0",
|
"typescript-eslint": "^8.58.0",
|
||||||
"vite": "^8.0.3",
|
"vite": "^8.0.5",
|
||||||
"vite-tsconfig-paths": "^6.1.1",
|
"vite-tsconfig-paths": "^6.1.1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -296,7 +296,7 @@
|
||||||
|
|
||||||
"@gcch/configuration-eslint": ["@gcch/configuration-eslint@git+https://git.gcch.fr/gcch/configuration-eslint#62ee424274f0bfebd5135a728960644f4b1cdcb8", { "dependencies": { "@eslint/js": "^10.0.1", "astro-eslint-parser": "^1.3.0", "eslint": "^10.0.3", "eslint-plugin-astro": "^1.6.0", "eslint-plugin-functional": "^9.0.4", "eslint-plugin-jsdoc": "^62.8.0", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-perfectionist": "^5.6.0", "eslint-plugin-sonarjs": "^4.0.2", "eslint-plugin-unicorn": "^63.0.0", "globals": "^17.4.0", "typescript-eslint": "^8.57.0" }, "peerDependencies": { "eslint": "^10.0.3", "typescript": "^6.0.1-rc" } }, "62ee424274f0bfebd5135a728960644f4b1cdcb8"],
|
"@gcch/configuration-eslint": ["@gcch/configuration-eslint@git+https://git.gcch.fr/gcch/configuration-eslint#62ee424274f0bfebd5135a728960644f4b1cdcb8", { "dependencies": { "@eslint/js": "^10.0.1", "astro-eslint-parser": "^1.3.0", "eslint": "^10.0.3", "eslint-plugin-astro": "^1.6.0", "eslint-plugin-functional": "^9.0.4", "eslint-plugin-jsdoc": "^62.8.0", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-perfectionist": "^5.6.0", "eslint-plugin-sonarjs": "^4.0.2", "eslint-plugin-unicorn": "^63.0.0", "globals": "^17.4.0", "typescript-eslint": "^8.57.0" }, "peerDependencies": { "eslint": "^10.0.3", "typescript": "^6.0.1-rc" } }, "62ee424274f0bfebd5135a728960644f4b1cdcb8"],
|
||||||
|
|
||||||
"@gcch/configuration-oxlint": ["@gcch/configuration-oxlint@git+https://git.gcch.fr/gcch/configuration-oxlint#3e49f5e2fbfde01ad3d75acbff0da8023d5a3802", { "dependencies": { "eslint-plugin-astro": "^1.6.0", "eslint-plugin-functional": "^9.0.4", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-perfectionist": "^5.8.0", "eslint-plugin-sonarjs": "^4.0.2", "globals": "^17.4.0", "oxlint": "^1.58.0", "oxlint-tsgolint": "^0.19.0" }, "peerDependencies": { "eslint-plugin-astro": "^1.6.0", "eslint-plugin-functional": "^9.0.4", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-perfectionist": "^5.8.0", "eslint-plugin-sonarjs": "^4.0.2", "oxlint": "^1.58.0", "oxlint-tsgolint": "^0.19.0", "typescript": "^6.0.2" } }, "3e49f5e2fbfde01ad3d75acbff0da8023d5a3802"],
|
"@gcch/configuration-oxlint": ["@gcch/configuration-oxlint@git+https://git.gcch.fr/gcch/configuration-oxlint#bedd1fa23affdb4c8ac4d3b39c4cc095791a3c05", { "dependencies": { "eslint-plugin-astro": "^1.6.0", "eslint-plugin-functional": "^9.0.4", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-perfectionist": "^5.8.0", "eslint-plugin-sonarjs": "^4.0.2", "globals": "^17.4.0", "oxlint": "^1.58.0", "oxlint-tsgolint": "^0.19.0" }, "peerDependencies": { "eslint-plugin-astro": "^1.6.0", "eslint-plugin-functional": "^9.0.4", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-perfectionist": "^5.8.0", "eslint-plugin-sonarjs": "^4.0.2", "oxlint": "^1.58.0", "oxlint-tsgolint": "^0.19.0", "typescript": "^6.0.2" } }, "bedd1fa23affdb4c8ac4d3b39c4cc095791a3c05"],
|
||||||
|
|
||||||
"@gcch/configuration-prettier": ["@gcch/configuration-prettier@git+https://git.gcch.fr/gcch/configuration-prettier#8de937e801bd44784ac91e0ff6e038d838f7eea1", { "dependencies": { "prettier": "^3.8.1", "prettier-plugin-curly": "^0.4.1", "prettier-plugin-ini": "^1.3.0", "prettier-plugin-jsdoc": "^1.8.0", "prettier-plugin-pkg": "^0.22.0", "prettier-plugin-sh": "^0.18.0", "prettier-plugin-sort-json": "^4.2.0" }, "peerDependencies": { "prettier": "^3.8.1" } }, "8de937e801bd44784ac91e0ff6e038d838f7eea1"],
|
"@gcch/configuration-prettier": ["@gcch/configuration-prettier@git+https://git.gcch.fr/gcch/configuration-prettier#8de937e801bd44784ac91e0ff6e038d838f7eea1", { "dependencies": { "prettier": "^3.8.1", "prettier-plugin-curly": "^0.4.1", "prettier-plugin-ini": "^1.3.0", "prettier-plugin-jsdoc": "^1.8.0", "prettier-plugin-pkg": "^0.22.0", "prettier-plugin-sh": "^0.18.0", "prettier-plugin-sort-json": "^4.2.0" }, "peerDependencies": { "prettier": "^3.8.1" } }, "8de937e801bd44784ac91e0ff6e038d838f7eea1"],
|
||||||
|
|
||||||
|
|
@ -510,7 +510,7 @@
|
||||||
|
|
||||||
"@playwright/test": ["@playwright/test@1.59.1", "", { "dependencies": { "playwright": "1.59.1" }, "bin": { "playwright": "cli.js" } }, "sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg=="],
|
"@playwright/test": ["@playwright/test@1.59.1", "", { "dependencies": { "playwright": "1.59.1" }, "bin": { "playwright": "cli.js" } }, "sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg=="],
|
||||||
|
|
||||||
"@reteps/dockerfmt": ["@reteps/dockerfmt@0.3.6", "", {}, "sha512-Tb5wIMvBf/nLejTQ61krK644/CEMB/cpiaIFXqGApfGqO3GwcR3qnI0DbmkFVCl2OyEp8LnLX3EkucoL0+tbFg=="],
|
"@reteps/dockerfmt": ["@reteps/dockerfmt@0.5.2", "", {}, "sha512-Hbr7yen4fP5TxGM54ucXa4o5NwWXatJ6Bd9I8gp0PValYbI4Rug2Gu+rVv7K7o/efQc3F5ctqWJz47rYaa8zBw=="],
|
||||||
|
|
||||||
"@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.12", "", { "os": "android", "cpu": "arm64" }, "sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA=="],
|
"@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.12", "", { "os": "android", "cpu": "arm64" }, "sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA=="],
|
||||||
|
|
||||||
|
|
@ -726,7 +726,7 @@
|
||||||
|
|
||||||
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
|
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
|
||||||
|
|
||||||
"caniuse-lite": ["caniuse-lite@1.0.30001785", "", {}, "sha512-blhOL/WNR+Km1RI/LCVAvA73xplXA7ZbjzI4YkMK9pa6T/P3F2GxjNpEkyw5repTw9IvkyrjyHpwjnhZ5FOvYQ=="],
|
"caniuse-lite": ["caniuse-lite@1.0.30001786", "", {}, "sha512-4oxTZEvqmLLrERwxO76yfKM7acZo310U+v4kqexI2TL1DkkUEMT8UijrxxcnVdxR3qkVf5awGRX+4Z6aPHVKrA=="],
|
||||||
|
|
||||||
"change-case": ["change-case@5.4.4", "", {}, "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w=="],
|
"change-case": ["change-case@5.4.4", "", {}, "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w=="],
|
||||||
|
|
||||||
|
|
@ -1318,7 +1318,7 @@
|
||||||
|
|
||||||
"prettier-plugin-pkg": ["prettier-plugin-pkg@0.22.1", "", { "peerDependencies": { "prettier": "^3.0.3" } }, "sha512-l9qnxic48hgTXsvXi9yWWWzovpqkEYo/Ljf8Af7zSkDTNVmLwscXW63IEVMJXH94DyloO8YkogeLheJUzJh/ZQ=="],
|
"prettier-plugin-pkg": ["prettier-plugin-pkg@0.22.1", "", { "peerDependencies": { "prettier": "^3.0.3" } }, "sha512-l9qnxic48hgTXsvXi9yWWWzovpqkEYo/Ljf8Af7zSkDTNVmLwscXW63IEVMJXH94DyloO8YkogeLheJUzJh/ZQ=="],
|
||||||
|
|
||||||
"prettier-plugin-sh": ["prettier-plugin-sh@0.18.0", "", { "dependencies": { "@reteps/dockerfmt": "^0.3.6", "sh-syntax": "^0.5.8" }, "peerDependencies": { "prettier": "^3.6.0" } }, "sha512-cW1XL27FOJQ/qGHOW6IHwdCiNWQsAgK+feA8V6+xUTaH0cD3Mh+tFAtBvEEWvuY6hTDzRV943Fzeii+qMOh7nQ=="],
|
"prettier-plugin-sh": ["prettier-plugin-sh@0.18.1", "", { "dependencies": { "@reteps/dockerfmt": "^0.5.1", "sh-syntax": "^0.5.8" }, "peerDependencies": { "prettier": "^3.6.0" } }, "sha512-uZmU22wBMevjh3rmCatNQqiEer2+5KLa0xYCBX6zQQUQkcNzVL+s6FbPKK6ZSUNUbQk6jMAcQHrYPvuL2W6ihQ=="],
|
||||||
|
|
||||||
"prettier-plugin-sort-json": ["prettier-plugin-sort-json@4.2.0", "", { "peerDependencies": { "prettier": "^3.0.0" } }, "sha512-jK1w3/7otTvHtv1eoLji2U9mEoOGeyl7QQQ/afLnjht1YtRLSUUk8o0rIIC/HUVXhoGPCFe4SVZbRGYjjUVgvA=="],
|
"prettier-plugin-sort-json": ["prettier-plugin-sort-json@4.2.0", "", { "peerDependencies": { "prettier": "^3.0.0" } }, "sha512-jK1w3/7otTvHtv1eoLji2U9mEoOGeyl7QQQ/afLnjht1YtRLSUUk8o0rIIC/HUVXhoGPCFe4SVZbRGYjjUVgvA=="],
|
||||||
|
|
||||||
|
|
@ -1588,7 +1588,7 @@
|
||||||
|
|
||||||
"varint": ["varint@6.0.0", "", {}, "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg=="],
|
"varint": ["varint@6.0.0", "", {}, "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg=="],
|
||||||
|
|
||||||
"vite": ["vite@8.0.3", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.8", "rolldown": "1.0.0-rc.12", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.0", "esbuild": "^0.27.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ=="],
|
"vite": ["vite@8.0.5", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.8", "rolldown": "1.0.0-rc.12", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-nmu43Qvq9UopTRfMx2jOYW5l16pb3iDC1JH6yMuPkpVbzK0k+L7dfsEDH4jRgYFmsg0sTAqkojoZgzLMlwHsCQ=="],
|
||||||
|
|
||||||
"vite-tsconfig-paths": ["vite-tsconfig-paths@6.1.1", "", { "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", "tsconfck": "^3.0.3" }, "peerDependencies": { "vite": "*" } }, "sha512-2cihq7zliibCCZ8P9cKJrQBkfgdvcFkOOc3Y02o3GWUDLgqjWsZudaoiuOwO/gzTzy17cS5F7ZPo4bsnS4DGkg=="],
|
"vite-tsconfig-paths": ["vite-tsconfig-paths@6.1.1", "", { "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", "tsconfck": "^3.0.3" }, "peerDependencies": { "vite": "*" } }, "sha512-2cihq7zliibCCZ8P9cKJrQBkfgdvcFkOOc3Y02o3GWUDLgqjWsZudaoiuOwO/gzTzy17cS5F7ZPo4bsnS4DGkg=="],
|
||||||
|
|
||||||
|
|
@ -1634,6 +1634,8 @@
|
||||||
|
|
||||||
"@gcch/configuration-eslint/eslint": ["eslint@10.1.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", "@eslint/config-array": "^0.23.3", "@eslint/config-helpers": "^0.5.3", "@eslint/core": "^1.1.1", "@eslint/plugin-kit": "^0.6.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^9.1.2", "eslint-visitor-keys": "^5.0.1", "espree": "^11.2.0", "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "minimatch": "^10.2.4", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-S9jlY/ELKEUwwQnqWDO+f+m6sercqOPSqXM5Go94l7DOmxHVDgmSFGWEzeE/gwgTAr0W103BWt0QLe/7mabIvA=="],
|
"@gcch/configuration-eslint/eslint": ["eslint@10.1.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", "@eslint/config-array": "^0.23.3", "@eslint/config-helpers": "^0.5.3", "@eslint/core": "^1.1.1", "@eslint/plugin-kit": "^0.6.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^9.1.2", "eslint-visitor-keys": "^5.0.1", "espree": "^11.2.0", "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "minimatch": "^10.2.4", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-S9jlY/ELKEUwwQnqWDO+f+m6sercqOPSqXM5Go94l7DOmxHVDgmSFGWEzeE/gwgTAr0W103BWt0QLe/7mabIvA=="],
|
||||||
|
|
||||||
|
"@gcch/configuration-prettier/prettier-plugin-sh": ["prettier-plugin-sh@0.18.0", "", { "dependencies": { "@reteps/dockerfmt": "^0.3.6", "sh-syntax": "^0.5.8" }, "peerDependencies": { "prettier": "^3.6.0" } }, "sha512-cW1XL27FOJQ/qGHOW6IHwdCiNWQsAgK+feA8V6+xUTaH0cD3Mh+tFAtBvEEWvuY6hTDzRV943Fzeii+qMOh7nQ=="],
|
||||||
|
|
||||||
"@keyv/bigmap/keyv": ["keyv@5.6.0", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw=="],
|
"@keyv/bigmap/keyv": ["keyv@5.6.0", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw=="],
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
|
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
|
||||||
|
|
@ -1702,6 +1704,8 @@
|
||||||
|
|
||||||
"@gcch/configuration-eslint/eslint/@eslint/plugin-kit": ["@eslint/plugin-kit@0.6.1", "", { "dependencies": { "@eslint/core": "^1.1.1", "levn": "^0.4.1" } }, "sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ=="],
|
"@gcch/configuration-eslint/eslint/@eslint/plugin-kit": ["@eslint/plugin-kit@0.6.1", "", { "dependencies": { "@eslint/core": "^1.1.1", "levn": "^0.4.1" } }, "sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ=="],
|
||||||
|
|
||||||
|
"@gcch/configuration-prettier/prettier-plugin-sh/@reteps/dockerfmt": ["@reteps/dockerfmt@0.3.6", "", {}, "sha512-Tb5wIMvBf/nLejTQ61krK644/CEMB/cpiaIFXqGApfGqO3GwcR3qnI0DbmkFVCl2OyEp8LnLX3EkucoL0+tbFg=="],
|
||||||
|
|
||||||
"eslint-plugin-jsx-a11y/minimatch/brace-expansion": ["brace-expansion@1.1.13", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w=="],
|
"eslint-plugin-jsx-a11y/minimatch/brace-expansion": ["brace-expansion@1.1.13", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w=="],
|
||||||
|
|
||||||
"stylelint/file-entry-cache/flat-cache": ["flat-cache@6.1.22", "", { "dependencies": { "cacheable": "^2.3.4", "flatted": "^3.4.2", "hookified": "^1.15.0" } }, "sha512-N2dnzVJIphnNsjHcrxGW7DePckJ6haPrSFqpsBUhHYgwtKGVq4JrBGielEGD2fCVnsGm1zlBVZ8wGhkyuetgug=="],
|
"stylelint/file-entry-cache/flat-cache": ["flat-cache@6.1.22", "", { "dependencies": { "cacheable": "^2.3.4", "flatted": "^3.4.2", "hookified": "^1.15.0" } }, "sha512-N2dnzVJIphnNsjHcrxGW7DePckJ6haPrSFqpsBUhHYgwtKGVq4JrBGielEGD2fCVnsGm1zlBVZ8wGhkyuetgug=="],
|
||||||
|
|
|
||||||
4
justfile
4
justfile
|
|
@ -81,7 +81,7 @@ watch-css:
|
||||||
# Compile TypeScript en JavaScript.
|
# Compile TypeScript en JavaScript.
|
||||||
[group('js')]
|
[group('js')]
|
||||||
build-js:
|
build-js:
|
||||||
@bun --bun vite build --config "cfg/vite.config.ts"
|
bun --bun vite build --config "cfg/vite.config.ts"
|
||||||
|
|
||||||
# Compile tout.
|
# Compile tout.
|
||||||
[group('css')]
|
[group('css')]
|
||||||
|
|
@ -94,7 +94,7 @@ build-all:
|
||||||
# Compile TypeScript à chaque changement de fichier.
|
# Compile TypeScript à chaque changement de fichier.
|
||||||
[group('js')]
|
[group('js')]
|
||||||
watch-js:
|
watch-js:
|
||||||
bun vite build --watch
|
bun --bun vite build --config "cfg/vite.config.ts" --watch
|
||||||
|
|
||||||
# Vérifie le code TypeScript avec des analyseurs statiques.
|
# Vérifie le code TypeScript avec des analyseurs statiques.
|
||||||
[group('js')]
|
[group('js')]
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@effect/language-service": "^0.84.3",
|
"@effect/language-service": "^0.84.3",
|
||||||
"@gcch/configuration-eslint": "git+https://git.gcch.fr/gcch/configuration-eslint#62ee424274",
|
"@gcch/configuration-eslint": "git+https://git.gcch.fr/gcch/configuration-eslint#62ee424274",
|
||||||
"@gcch/configuration-oxlint": "git+https://git.gcch.fr/gcch/configuration-oxlint#3e49f5e2fb",
|
"@gcch/configuration-oxlint": "git+https://git.gcch.fr/gcch/configuration-oxlint#bedd1fa23aff",
|
||||||
"@gcch/configuration-prettier": "git+https://git.gcch.fr/gcch/configuration-prettier#8de937e801",
|
"@gcch/configuration-prettier": "git+https://git.gcch.fr/gcch/configuration-prettier#8de937e801",
|
||||||
"@playwright/test": "^1.59.1",
|
"@playwright/test": "^1.59.1",
|
||||||
"@sentry/core": "^10.47.0",
|
"@sentry/core": "^10.47.0",
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
"@vitejs/plugin-legacy": "^8.0.1",
|
"@vitejs/plugin-legacy": "^8.0.1",
|
||||||
"better-typescript-lib": "^2.12.0",
|
"better-typescript-lib": "^2.12.0",
|
||||||
"browserslist": "^4.28.2",
|
"browserslist": "^4.28.2",
|
||||||
"caniuse-lite": "^1.0.30001785",
|
"caniuse-lite": "^1.0.30001786",
|
||||||
"eslint": "^10.2.0",
|
"eslint": "^10.2.0",
|
||||||
"eslint-plugin-functional": "^9.0.4",
|
"eslint-plugin-functional": "^9.0.4",
|
||||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||||
|
|
@ -50,7 +50,7 @@
|
||||||
"playwright": "^1.59.1",
|
"playwright": "^1.59.1",
|
||||||
"prettier": "^3.8.1",
|
"prettier": "^3.8.1",
|
||||||
"prettier-plugin-pkg": "^0.22.1",
|
"prettier-plugin-pkg": "^0.22.1",
|
||||||
"prettier-plugin-sh": "^0.18.0",
|
"prettier-plugin-sh": "^0.18.1",
|
||||||
"sass-embedded": "^1.99.0",
|
"sass-embedded": "^1.99.0",
|
||||||
"stylelint": "^17.6.0",
|
"stylelint": "^17.6.0",
|
||||||
"stylelint-config-clean-order": "^8.0.1",
|
"stylelint-config-clean-order": "^8.0.1",
|
||||||
|
|
@ -60,7 +60,7 @@
|
||||||
"stylelint-plugin-logical-css": "^2.1.0",
|
"stylelint-plugin-logical-css": "^2.1.0",
|
||||||
"typescript": "6.0.2",
|
"typescript": "6.0.2",
|
||||||
"typescript-eslint": "^8.58.0",
|
"typescript-eslint": "^8.58.0",
|
||||||
"vite": "^8.0.3",
|
"vite": "^8.0.5",
|
||||||
"vite-tsconfig-paths": "^6.1.1"
|
"vite-tsconfig-paths": "^6.1.1"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ parameters:
|
||||||
reportWrongPhpDocTypeInVarTag: true
|
reportWrongPhpDocTypeInVarTag: true
|
||||||
# Setting treatPhpDocTypesAsCertain to false relaxes some of the rules around type-checking.
|
# Setting treatPhpDocTypesAsCertain to false relaxes some of the rules around type-checking.
|
||||||
treatPhpDocTypesAsCertain: true
|
treatPhpDocTypesAsCertain: true
|
||||||
|
# PHP silently casts array keys that look like decimal integers from string to int. This means array<string, mixed> can’t guarantee that keys are actually strings at runtime.
|
||||||
|
reportUnsafeArrayStringKeyCasting: true
|
||||||
|
|
||||||
parallel:
|
parallel:
|
||||||
jobSize: 20
|
jobSize: 20
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,4 @@ function load_page_resources(): void {
|
||||||
|
|
||||||
add_action('wp_enqueue_scripts', load_page_resources(...));
|
add_action('wp_enqueue_scripts', load_page_resources(...));
|
||||||
|
|
||||||
Timber::render(
|
Timber::render(data: $context, filenames: $templates);
|
||||||
data: $context,
|
|
||||||
filenames: $templates,
|
|
||||||
);
|
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,7 @@ $templates = ['boutique.twig'];
|
||||||
/** @var list<WC_Product> $wc_products Les informations brutes des Produits. */
|
/** @var list<WC_Product> $wc_products Les informations brutes des Produits. */
|
||||||
$wc_products = wc_get_products(['limit' => 12, 'order' => 'DESC', 'orderby' => 'date', 'status' => 'publish']);
|
$wc_products = wc_get_products(['limit' => 12, 'order' => 'DESC', 'orderby' => 'date', 'status' => 'publish']);
|
||||||
|
|
||||||
$products = array_map(
|
$products = array_map(callback: Product::from_wc_product(...), array: $wc_products);
|
||||||
callback: Product::new(...),
|
|
||||||
array: $wc_products,
|
|
||||||
);
|
|
||||||
$context['products'] = $products;
|
$context['products'] = $products;
|
||||||
|
|
||||||
add_action('wp_enqueue_scripts', function (): void {
|
add_action('wp_enqueue_scripts', function (): void {
|
||||||
|
|
@ -44,7 +41,4 @@ add_action('wp_enqueue_scripts', function (): void {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Timber::render(
|
Timber::render(data: $context, filenames: $templates);
|
||||||
data: $context,
|
|
||||||
filenames: $templates,
|
|
||||||
);
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,4 @@ add_action('wp_enqueue_scripts', function (): void {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Timber::render(
|
Timber::render(data: $context, filenames: $templates);
|
||||||
data: $context,
|
|
||||||
filenames: $templates,
|
|
||||||
);
|
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,6 @@ Timber::$dirname = ['views'];
|
||||||
|
|
||||||
// Charge les Scripts du thème (report d'erreurs)
|
// Charge les Scripts du thème (report d'erreurs)
|
||||||
function load_scripts(): void {
|
function load_scripts(): void {
|
||||||
// wp_enqueue_script_module(
|
|
||||||
// id: 'haiku-atelier-2024-gaffe',
|
|
||||||
// deps: [],
|
|
||||||
// src: get_template_directory_uri() . '/assets/js/gaffe.js',
|
|
||||||
// version: filemtime(get_template_directory() . '/assets/js/gaffe.js'),
|
|
||||||
// );
|
|
||||||
wp_enqueue_script_module(
|
wp_enqueue_script_module(
|
||||||
id: 'haiku-atelier-2024-bouton-panier',
|
id: 'haiku-atelier-2024-bouton-panier',
|
||||||
deps: [],
|
deps: [],
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,4 @@ use Timber\Timber;
|
||||||
$context = Timber::context();
|
$context = Timber::context();
|
||||||
$templates = ['base.twig'];
|
$templates = ['base.twig'];
|
||||||
|
|
||||||
Timber::render(
|
Timber::render(data: $context, filenames: $templates);
|
||||||
data: $context,
|
|
||||||
filenames: $templates,
|
|
||||||
);
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,4 @@ add_action('wp_enqueue_scripts', function (): void {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Timber::render(
|
Timber::render(data: $context, filenames: $templates);
|
||||||
data: $context,
|
|
||||||
filenames: $templates,
|
|
||||||
);
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ declare(strict_types=1);
|
||||||
namespace HaikuAtelier;
|
namespace HaikuAtelier;
|
||||||
|
|
||||||
use HaikuAtelier\Data\Cart;
|
use HaikuAtelier\Data\Cart;
|
||||||
|
use HaikuAtelier\Data\Product;
|
||||||
use HaikuAtelier\WP\Resource;
|
use HaikuAtelier\WP\Resource;
|
||||||
use Illuminate\Support\Number;
|
use Illuminate\Support\Number;
|
||||||
use Timber\Timber;
|
use Timber\Timber;
|
||||||
|
|
@ -17,13 +18,8 @@ use WC_Shipping_Rate;
|
||||||
use function add_action;
|
use function add_action;
|
||||||
use function collect;
|
use function collect;
|
||||||
use function Crell\fp\pipe;
|
use function Crell\fp\pipe;
|
||||||
use function genere_balise_img_multiformats;
|
|
||||||
use function recupere_et_formate_attributs_produit;
|
|
||||||
use function WC;
|
use function WC;
|
||||||
|
|
||||||
// Importe la fonction pour récupérer les informations affichées des Produits dans le Panier
|
|
||||||
require_once __DIR__ . '/src/inc/TraitementInformations.php';
|
|
||||||
|
|
||||||
$context = Timber::context();
|
$context = Timber::context();
|
||||||
$templates = ['panier.twig'];
|
$templates = ['panier.twig'];
|
||||||
|
|
||||||
|
|
@ -52,12 +48,12 @@ $shipping_subtotal = Cart::parse_cart_value($cart_totals['shipping_total'] ?? 0)
|
||||||
foreach (WC()->cart->get_cart() as $cle_panier => $article_panier) {
|
foreach (WC()->cart->get_cart() as $cle_panier => $article_panier) {
|
||||||
$cart[$cle_panier] = [
|
$cart[$cle_panier] = [
|
||||||
'attributs' => $article_panier['data']?->get_type() === 'variation'
|
'attributs' => $article_panier['data']?->get_type() === 'variation'
|
||||||
? recupere_et_formate_attributs_produit($article_panier['data']?->get_attributes())
|
? Product::recupere_et_formate_attributs_produit($article_panier['data']?->get_attributes())
|
||||||
: [],
|
: [],
|
||||||
'cle' => $cle_panier,
|
'cle' => $cle_panier,
|
||||||
'id_produit' => $article_panier['product_id'],
|
'id_produit' => $article_panier['product_id'],
|
||||||
'id_variation' => $article_panier['variation_id'],
|
'id_variation' => $article_panier['variation_id'],
|
||||||
'image' => pipe($article_panier['data']?->get_image_id(), static fn($id): string => genere_balise_img_multiformats(
|
'image' => pipe($article_panier['data']?->get_image_id(), static fn($id): string => Resource::output_multi_formats_img_tag(
|
||||||
id: (string) $id,
|
id: (string) $id,
|
||||||
lazy: true,
|
lazy: true,
|
||||||
)),
|
)),
|
||||||
|
|
@ -110,7 +106,4 @@ add_action('wp_enqueue_scripts', function (): void {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Rendu
|
// Rendu
|
||||||
Timber::render(
|
Timber::render(filenames: $templates, data: $context);
|
||||||
filenames: $templates,
|
|
||||||
data: $context,
|
|
||||||
);
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,4 @@ add_action('wp_enqueue_scripts', function (): void {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Rendu
|
// Rendu
|
||||||
Timber::render(
|
Timber::render(filenames: $templates, data: $context);
|
||||||
filenames: $templates,
|
|
||||||
data: $context,
|
|
||||||
);
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,4 @@ add_action('wp_enqueue_scripts', function (): void {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Rendu
|
// Rendu
|
||||||
Timber::render(
|
Timber::render(filenames: $templates, data: $context);
|
||||||
filenames: $templates,
|
|
||||||
data: $context,
|
|
||||||
);
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace HaikuAtelier;
|
namespace HaikuAtelier;
|
||||||
|
|
||||||
|
use HaikuAtelier\WP\Resource;
|
||||||
use Roots\WPConfig\Config;
|
use Roots\WPConfig\Config;
|
||||||
use Stripe\Checkout\Session;
|
use Stripe\Checkout\Session;
|
||||||
use Stripe\StripeClient;
|
use Stripe\StripeClient;
|
||||||
|
|
@ -18,8 +19,6 @@ use WC_Order_Refund;
|
||||||
|
|
||||||
use function Crell\fp\pipe;
|
use function Crell\fp\pipe;
|
||||||
|
|
||||||
require_once __DIR__ . '/src/inc/TraitementInformations.php';
|
|
||||||
|
|
||||||
/** @var string $url_accueil L'URL de la page d'Accueil. */
|
/** @var string $url_accueil L'URL de la page d'Accueil. */
|
||||||
$url_accueil = get_page_link(get_page_by_path('home')?->ID);
|
$url_accueil = get_page_link(get_page_by_path('home')?->ID);
|
||||||
|
|
||||||
|
|
@ -87,7 +86,7 @@ try {
|
||||||
return [
|
return [
|
||||||
'attribut' => $attribut,
|
'attribut' => $attribut,
|
||||||
'id_produit' => $id_produit,
|
'id_produit' => $id_produit,
|
||||||
'image' => pipe($produit->get_image_id(), static fn($id): string => genere_balise_img_multiformats(
|
'image' => pipe($produit->get_image_id(), static fn($id): string => Resource::output_multi_formats_img_tag(
|
||||||
id: $id,
|
id: $id,
|
||||||
lazy: true,
|
lazy: true,
|
||||||
)),
|
)),
|
||||||
|
|
@ -114,10 +113,7 @@ try {
|
||||||
add_action('wp_enqueue_scripts', 'charge_scripts_styles_page_succes_commande');
|
add_action('wp_enqueue_scripts', 'charge_scripts_styles_page_succes_commande');
|
||||||
|
|
||||||
// Rendu
|
// Rendu
|
||||||
Timber::render(
|
Timber::render(filenames: $templates, data: $context);
|
||||||
filenames: $templates,
|
|
||||||
data: $context,
|
|
||||||
);
|
|
||||||
} catch (Error $error) {
|
} catch (Error $error) {
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
echo json_encode(['error' => esc_html($error->getMessage())]);
|
echo json_encode(['error' => esc_html($error->getMessage())]);
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,4 @@ add_action('wp_enqueue_scripts', function (): void {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Rendu
|
// Rendu
|
||||||
Timber::render(
|
Timber::render(filenames: $templates, data: $context);
|
||||||
filenames: $templates,
|
|
||||||
data: $context,
|
|
||||||
);
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,9 @@ namespace HaikuAtelier;
|
||||||
use Exception;
|
use Exception;
|
||||||
use HaikuAtelier\Data\Product;
|
use HaikuAtelier\Data\Product;
|
||||||
use HaikuAtelier\WP\Resource;
|
use HaikuAtelier\WP\Resource;
|
||||||
|
use HaikuAtelier\WP\Term;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
|
use Psl\Option\Option;
|
||||||
use stdClass;
|
use stdClass;
|
||||||
use Timber\Timber;
|
use Timber\Timber;
|
||||||
use WC_Product;
|
use WC_Product;
|
||||||
|
|
@ -20,12 +22,9 @@ use function add_action;
|
||||||
use function assert;
|
use function assert;
|
||||||
use function collect;
|
use function collect;
|
||||||
use function is_array;
|
use function is_array;
|
||||||
use function recupere_produits_meme_collection;
|
|
||||||
use function wc_get_product;
|
use function wc_get_product;
|
||||||
use function wp_json_encode;
|
use function wp_json_encode;
|
||||||
|
|
||||||
require_once __DIR__ . '/src/inc/TraitementInformations.php';
|
|
||||||
|
|
||||||
$context = Timber::context();
|
$context = Timber::context();
|
||||||
$templates = ['produit.twig'];
|
$templates = ['produit.twig'];
|
||||||
|
|
||||||
|
|
@ -37,23 +36,41 @@ if ($raw_product === null || $raw_product === false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assemble les données d'intérêt pour la page au sein d'une Classe.
|
// Assemble les données d'intérêt pour la page au sein d'une Classe.
|
||||||
$product = Product::new($raw_product);
|
$product = Product::from_wc_product($raw_product);
|
||||||
|
|
||||||
/** @var int $maximum_price Le prix de la Variation la plus chère */
|
/** @var int $maximum_price Le prix de la Variation la plus chère */
|
||||||
$maximum_price = collect($product->variations)->max('price');
|
$maximum_price = collect($product->variations)->max('price');
|
||||||
|
|
||||||
/** @var list<Product> Les Produits de la même collection que celui affiché dans la Page. */
|
/** @var list<Product> Les Produits de la même collection que celui affiché dans la Page. */
|
||||||
$same_collection_products = recupere_produits_meme_collection($product->collection)($product->id)
|
$same_collection_products = Product::get_same_collection_products($product->collection)($product->id)
|
||||||
|> function (/** @var list<WC_Product>|stdClass */ mixed $products): array {
|
|> function (/** @var list<WC_Product>|stdClass */ mixed $products): array {
|
||||||
assert(is_array($products), 'Les Produits de la même collection doivent être un tableau.');
|
assert(is_array($products), 'Les Produits de la même collection doivent être un tableau.');
|
||||||
return $products;
|
return $products;
|
||||||
}
|
}
|
||||||
|> (static fn(/** @var list<WC_Product> */ array $products): array => Arr::map($products, Product::new(...)));
|
|> (static fn(/** @var list<WC_Product> */ array $products): array => Arr::map(
|
||||||
|
$products,
|
||||||
|
Product::from_wc_product(...),
|
||||||
|
));
|
||||||
|
|
||||||
$context['product'] = $product;
|
$context['product'] = $product;
|
||||||
$context['product_json'] = wp_json_encode($product);
|
$context['product_json'] = wp_json_encode($product);
|
||||||
$context['maximum_price'] = $maximum_price;
|
$context['maximum_price'] = $maximum_price;
|
||||||
$context['same_collection_products'] = $same_collection_products;
|
$context['same_collection_products'] = $same_collection_products;
|
||||||
|
$product_tags = $raw_product->get_tag_ids()
|
||||||
|
|> (static fn($tags_ids) => Arr::map($tags_ids, static fn($id) => Term::get_term_by_id(
|
||||||
|
id: $id,
|
||||||
|
taxonomy: 'product_tag',
|
||||||
|
)))
|
||||||
|
|> (static fn(/** @var list<Option<WC_Term>> */ $tags) => Arr::reject($tags, static fn($tag) => $tag->isNone()))
|
||||||
|
|> (static fn(/** @var list<Option<WC_Term>> */ $tags) => Arr::map($tags, static fn($tag) => $tag->unwrap()));
|
||||||
|
$tags = get_terms(['taxonomy' => 'product_tag', 'hide_empty' => true]);
|
||||||
|
|
||||||
|
echo '<pre>';
|
||||||
|
print_r($product_tags);
|
||||||
|
print_r($tags);
|
||||||
|
echo '</pre>';
|
||||||
|
|
||||||
|
exit();
|
||||||
|
|
||||||
add_action('wp_enqueue_scripts', function (): void {
|
add_action('wp_enqueue_scripts', function (): void {
|
||||||
Resource::enqueue_script_module_file(
|
Resource::enqueue_script_module_file(
|
||||||
|
|
@ -67,7 +84,4 @@ add_action('wp_enqueue_scripts', function (): void {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Rendu
|
// Rendu
|
||||||
Timber::render(
|
Timber::render(filenames: $templates, data: $context);
|
||||||
filenames: $templates,
|
|
||||||
data: $context,
|
|
||||||
);
|
|
||||||
|
|
|
||||||
|
|
@ -94,22 +94,11 @@ final class StarterSite extends Site {
|
||||||
// Récupère la Page courante
|
// Récupère la Page courante
|
||||||
$url_courante = URLHelper::get_current_url();
|
$url_courante = URLHelper::get_current_url();
|
||||||
$context['page_courante'] = $url_courante;
|
$context['page_courante'] = $url_courante;
|
||||||
$context['est_page_tous_produits'] = preg_match(
|
$context['est_page_tous_produits'] = preg_match(pattern: '/(\bshop\b)/', subject: $url_courante);
|
||||||
pattern: '/(\bshop\b)/',
|
$context['est_page_boutique'] =
|
||||||
subject: $url_courante,
|
preg_match(pattern: '/(\bshop\b)/', subject: $url_courante)
|
||||||
);
|
|| preg_match(pattern: '/(\bproduct\b)/', subject: $url_courante)
|
||||||
$context['est_page_boutique'] = preg_match(
|
|| preg_match(pattern: '/(\bproduct-category\b)/', subject: $url_courante);
|
||||||
pattern: '/(\bshop\b)/',
|
|
||||||
subject: $url_courante,
|
|
||||||
)
|
|
||||||
|| preg_match(
|
|
||||||
pattern: '/(\bproduct\b)/',
|
|
||||||
subject: $url_courante,
|
|
||||||
)
|
|
||||||
|| preg_match(
|
|
||||||
pattern: '/(\bproduct-category\b)/',
|
|
||||||
subject: $url_courante,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Politique de confidentialité
|
// Politique de confidentialité
|
||||||
$politique_confidentialite_lien = pipe(get_privacy_policy_url(), esc_url(...));
|
$politique_confidentialite_lien = pipe(get_privacy_policy_url(), esc_url(...));
|
||||||
|
|
@ -130,10 +119,7 @@ final class StarterSite extends Site {
|
||||||
];
|
];
|
||||||
$entrees_menu_categories = pipe(
|
$entrees_menu_categories = pipe(
|
||||||
get_categories(['hide_empty' => false, 'orderby' => 'menu_order', 'taxonomy' => 'product_cat']),
|
get_categories(['hide_empty' => false, 'orderby' => 'menu_order', 'taxonomy' => 'product_cat']),
|
||||||
static fn($categories): array => array_map(
|
static fn($categories): array => array_map(callback: $cree_entree_menu, array: $categories),
|
||||||
callback: $cree_entree_menu,
|
|
||||||
array: $categories,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
$context['categories_produits'] = $entrees_menu_categories;
|
$context['categories_produits'] = $entrees_menu_categories;
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,6 @@ final readonly class Attribute {
|
||||||
/** @var list<AttributeOption> */
|
/** @var list<AttributeOption> */
|
||||||
$options = Arr::map($terms, AttributeOption::new(...));
|
$options = Arr::map($terms, AttributeOption::new(...));
|
||||||
|
|
||||||
return new self(
|
return new self(name: $name, slug: $slug, options: $options);
|
||||||
name: $name,
|
|
||||||
slug: $slug,
|
|
||||||
options: $options,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,6 @@ final readonly class AttributeOption {
|
||||||
$name = $term->name;
|
$name = $term->name;
|
||||||
$slug = $term->slug;
|
$slug = $term->slug;
|
||||||
|
|
||||||
return new self(
|
return new self(id: $id, name: $name, slug: $slug);
|
||||||
id: $id,
|
|
||||||
name: $name,
|
|
||||||
slug: $slug,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,17 @@ declare(strict_types=1);
|
||||||
namespace HaikuAtelier\Data;
|
namespace HaikuAtelier\Data;
|
||||||
|
|
||||||
use HaikuAtelier\WP\HaikuProduct;
|
use HaikuAtelier\WP\HaikuProduct;
|
||||||
|
use HaikuAtelier\WP\Resource;
|
||||||
use HaikuAtelier\WP\Term;
|
use HaikuAtelier\WP\Term;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Psl\Option;
|
use Psl\Option;
|
||||||
|
use stdClass;
|
||||||
use WC_Product;
|
use WC_Product;
|
||||||
use WP_Term;
|
use WP_Term;
|
||||||
|
|
||||||
use function HaikuAtelier\genere_balise_img_multiformats;
|
|
||||||
use function head;
|
use function head;
|
||||||
use function Psl\Option\from_nullable;
|
use function Psl\Option\from_nullable;
|
||||||
|
use function wc_get_products;
|
||||||
use function wpautop;
|
use function wpautop;
|
||||||
|
|
||||||
final readonly class Product {
|
final readonly class Product {
|
||||||
|
|
@ -41,16 +43,7 @@ final readonly class Product {
|
||||||
public string $url,
|
public string $url,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
public static function from_wc_product(WC_Product $product): self {
|
||||||
* @return list<Attribute>
|
|
||||||
*/
|
|
||||||
public static function get_attributes_for_product(WC_Product $product): array {
|
|
||||||
/** @var list<Attribute> */
|
|
||||||
return $product->get_attributes()
|
|
||||||
|> (static fn(array $attributes): array => Arr::map($attributes, Attribute::new(...)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function new(WC_Product $product): self {
|
|
||||||
$attributes = self::get_attributes_for_product($product);
|
$attributes = self::get_attributes_for_product($product);
|
||||||
/** @var lowercase-string */
|
/** @var lowercase-string */
|
||||||
$category = $product->get_id() |> wc_get_product_category_list(...) |> strtolower(...);
|
$category = $product->get_id() |> wc_get_product_category_list(...) |> strtolower(...);
|
||||||
|
|
@ -73,8 +66,8 @@ final readonly class Product {
|
||||||
$left_column_photos = HaikuProduct::get_left_column_photos($id);
|
$left_column_photos = HaikuProduct::get_left_column_photos($id);
|
||||||
/** @var list<string> */
|
/** @var list<string> */
|
||||||
$right_column_photos = HaikuProduct::get_right_column_photos($id);
|
$right_column_photos = HaikuProduct::get_right_column_photos($id);
|
||||||
$default_photo = $left_column_photos[0] ?? genere_balise_img_multiformats('-1');
|
$default_photo = $left_column_photos[0] ?? Resource::output_multi_formats_img_tag('-1');
|
||||||
$hover_photo = $right_column_photos[0] ?? genere_balise_img_multiformats('-1', true);
|
$hover_photo = $right_column_photos[0] ?? Resource::output_multi_formats_img_tag('-1', true);
|
||||||
$slug = $product->get_slug();
|
$slug = $product->get_slug();
|
||||||
$stock = $product->get_stock_quantity() ?? 1;
|
$stock = $product->get_stock_quantity() ?? 1;
|
||||||
/** @var array<ProductVariation> */
|
/** @var array<ProductVariation> */
|
||||||
|
|
@ -104,4 +97,38 @@ final readonly class Product {
|
||||||
url: $url,
|
url: $url,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<Attribute>
|
||||||
|
*/
|
||||||
|
public static function get_attributes_for_product(WC_Product $product): array {
|
||||||
|
/** @var list<Attribute> */
|
||||||
|
return $product->get_attributes()
|
||||||
|
|> (static fn(array $attributes): array => Arr::map($attributes, Attribute::new(...)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère les informations utilisées pour la grille des Produits similaires (de la même
|
||||||
|
* collection) et les retourne sous forme de tableau associatif.
|
||||||
|
*
|
||||||
|
* Pour faciliter l'usage avec `array_map`, utilise une fonction avec curryfication.
|
||||||
|
*/
|
||||||
|
public static function get_same_collection_products(string $slug_collection): callable {
|
||||||
|
return static fn(int $id_produit): array|stdClass => wc_get_products([
|
||||||
|
'exclude' => [$id_produit],
|
||||||
|
'limit' => 4,
|
||||||
|
'order' => 'DESC',
|
||||||
|
'orderby' => 'date',
|
||||||
|
'status' => 'publish',
|
||||||
|
'tax_query' => [['taxonomy' => 'collection', 'field' => 'slug', 'terms' => $slug_collection]],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function recupere_et_formate_attributs_produit(mixed $attributs_produit): mixed {
|
||||||
|
return [
|
||||||
|
'taille' => ['nom' => 'Size', 'valeur' => $attributs_produit['pa_size'] ?? false],
|
||||||
|
'pierre' => ['nom' => 'Stone', 'valeur' => $attributs_produit['pa_stone'] ?? false],
|
||||||
|
'cote' => ['nom' => 'Side', 'valeur' => $attributs_produit['pa_side'] ?? false],
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
use function Crell\fp\pipe;
|
use HaikuAtelier\WP\Resource;
|
||||||
|
|
||||||
require_once 'TraitementInformations.php';
|
use function Crell\fp\pipe;
|
||||||
|
|
||||||
// Images du Produit
|
// Images du Produit
|
||||||
|
|
||||||
|
|
@ -145,13 +145,10 @@ function genere_balises_img_dans_produit_dans_reponse_rest(
|
||||||
array: $metadata,
|
array: $metadata,
|
||||||
callback: static fn($entree): bool => '_photos_colonne_gauche|||0|value' === $entree->key,
|
callback: static fn($entree): bool => '_photos_colonne_gauche|||0|value' === $entree->key,
|
||||||
),
|
),
|
||||||
static fn($metadata): array => array_map(
|
static fn($metadata): array => array_map(array: $metadata, callback: static fn($entree): string => Resource::output_multi_formats_img_tag(
|
||||||
array: $metadata,
|
id: $entree?->value,
|
||||||
callback: static fn($entree): string => genere_balise_img_multiformats(
|
lazy: true,
|
||||||
id: $entree?->value,
|
)),
|
||||||
lazy: true,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
static fn($image) => array_values(array: $image)[0],
|
static fn($image) => array_values(array: $image)[0],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -162,13 +159,10 @@ function genere_balises_img_dans_produit_dans_reponse_rest(
|
||||||
array: $metadata,
|
array: $metadata,
|
||||||
callback: static fn($entree): bool => '_photos_colonne_droite|||0|value' === $entree->key,
|
callback: static fn($entree): bool => '_photos_colonne_droite|||0|value' === $entree->key,
|
||||||
),
|
),
|
||||||
static fn($metadata): array => array_map(
|
static fn($metadata): array => array_map(array: $metadata, callback: static fn($entree): string => Resource::output_multi_formats_img_tag(
|
||||||
array: $metadata,
|
id: $entree?->value,
|
||||||
callback: static fn($entree): string => genere_balise_img_multiformats(
|
lazy: true,
|
||||||
id: $entree?->value,
|
)),
|
||||||
lazy: true,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
static fn($image) => array_values(array: $image)[0],
|
static fn($image) => array_values(array: $image)[0],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fonctions pour le traitement d'informations.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace HaikuAtelier;
|
|
||||||
|
|
||||||
use function Crell\fp\pipe;
|
|
||||||
|
|
||||||
// Page Shop
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO.
|
|
||||||
*
|
|
||||||
* @param string $id TODO
|
|
||||||
* @param bool $lazy TODO
|
|
||||||
*
|
|
||||||
* @return string TODO
|
|
||||||
*/
|
|
||||||
function genere_balise_img_multiformats(string $id, bool $lazy = false): string {
|
|
||||||
$int_id = (int) $id;
|
|
||||||
|
|
||||||
if (-1 === $int_id) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$url = wp_get_attachment_image_url($int_id, 'full');
|
|
||||||
$chemin = realpath(get_attached_file($int_id)) ?: realpath(get_attached_file($int_id));
|
|
||||||
$alt = get_post_meta($int_id, '_wp_attachment_image_alt', true);
|
|
||||||
$dimensions = $chemin ? getimagesize($chemin) : ['', ''];
|
|
||||||
|
|
||||||
$avif = $chemin ? realpath(pathinfo($chemin)['dirname'] . '/' . pathinfo($chemin)['filename'] . '.avif') : false;
|
|
||||||
$jxl = $chemin ? realpath(pathinfo($chemin)['dirname'] . '/' . pathinfo($chemin)['filename'] . '.jxl') : false;
|
|
||||||
|
|
||||||
// Génère un tableau avec les différents formats valides
|
|
||||||
$formats = pipe(
|
|
||||||
[$avif, $jxl],
|
|
||||||
static fn($tableau): array => array_filter(
|
|
||||||
array: $tableau,
|
|
||||||
callback: static fn($chemin_format): bool => false !== $chemin_format,
|
|
||||||
),
|
|
||||||
static fn($tableau): array => array_map(
|
|
||||||
array: $tableau,
|
|
||||||
callback: static fn($chemin_format): array => [
|
|
||||||
'format' => pathinfo((string) $chemin_format)['extension'],
|
|
||||||
'taille' => filesize($chemin_format),
|
|
||||||
'url' =>
|
|
||||||
pathinfo($url)['dirname']
|
|
||||||
. '/'
|
|
||||||
. pathinfo($url)['filename']
|
|
||||||
. '.'
|
|
||||||
. pathinfo((string) $chemin_format)['extension'],
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
usort(
|
|
||||||
array: $formats,
|
|
||||||
callback: static fn($a, $b): int => $a['taille'] <=> $b['taille'],
|
|
||||||
);
|
|
||||||
|
|
||||||
// Construis les balises <source> avec les formats valides
|
|
||||||
$sources = '';
|
|
||||||
foreach ($formats as $format) {
|
|
||||||
$height = $dimensions[0];
|
|
||||||
$width = $dimensions[1];
|
|
||||||
$sources .= "<source height='{$height}' srcset='{$format['url']}' type='image/{$format['format']}' width='{$width}' />\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
$loading = $lazy ? 'lazy' : 'eager';
|
|
||||||
|
|
||||||
return <<<EOD
|
|
||||||
{$sources}
|
|
||||||
|
|
||||||
<img
|
|
||||||
alt="{$alt}"
|
|
||||||
decoding="async"
|
|
||||||
height="{$dimensions[0]}"
|
|
||||||
loading="{$loading}"
|
|
||||||
onload="this.style.opacity=1"
|
|
||||||
src="{$url}"
|
|
||||||
width="{$dimensions[1]}"
|
|
||||||
/>
|
|
||||||
EOD;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Page Produit
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Récupère les informations utilisées pour la grille des Produits similaires (de la même
|
|
||||||
* collection) et les retourne sous forme de tableau associatif.
|
|
||||||
*
|
|
||||||
* Pour faciliter l'usage avec `array_map`, utilise une fonction avec curryfication.
|
|
||||||
*/
|
|
||||||
function recupere_produits_meme_collection(string $slug_collection): callable {
|
|
||||||
return static fn(int $id_produit): array|stdClass => wc_get_products([
|
|
||||||
'exclude' => [$id_produit],
|
|
||||||
'limit' => 4,
|
|
||||||
'order' => 'DESC',
|
|
||||||
'orderby' => 'date',
|
|
||||||
'status' => 'publish',
|
|
||||||
'tax_query' => [['taxonomy' => 'collection', 'field' => 'slug', 'terms' => $slug_collection]],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Page Panier
|
|
||||||
|
|
||||||
function recupere_et_formate_attributs_produit(mixed $attributs_produit): mixed {
|
|
||||||
return [
|
|
||||||
'taille' => ['nom' => 'Size', 'valeur' => $attributs_produit['pa_size'] ?? false],
|
|
||||||
'pierre' => ['nom' => 'Stone', 'valeur' => $attributs_produit['pa_stone'] ?? false],
|
|
||||||
'cote' => ['nom' => 'Side', 'valeur' => $attributs_produit['pa_side'] ?? false],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
@ -7,7 +7,6 @@ namespace HaikuAtelier\WP;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
|
|
||||||
use function carbon_get_post_meta;
|
use function carbon_get_post_meta;
|
||||||
use function HaikuAtelier\genere_balise_img_multiformats;
|
|
||||||
use function is_array;
|
use function is_array;
|
||||||
use function is_string;
|
use function is_string;
|
||||||
|
|
||||||
|
|
@ -19,7 +18,7 @@ final readonly class HaikuProduct {
|
||||||
/** @var list<string> */
|
/** @var list<string> */
|
||||||
return Post::get_post_meta_array($post_id, '_photos_colonne_gauche|||0|value')->unwrapOr([])
|
return Post::get_post_meta_array($post_id, '_photos_colonne_gauche|||0|value')->unwrapOr([])
|
||||||
|> (static fn(array $meta) => Arr::where($meta, static fn($meta): bool => is_string($meta)))
|
|> (static fn(array $meta) => Arr::where($meta, static fn($meta): bool => is_string($meta)))
|
||||||
|> (static fn(array $array) => Arr::map($array, genere_balise_img_multiformats(...)));
|
|> (static fn(array $array) => Arr::map($array, Resource::output_multi_formats_img_tag(...)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -31,7 +30,7 @@ final readonly class HaikuProduct {
|
||||||
if (is_array($meta)) {
|
if (is_array($meta)) {
|
||||||
/** @var list<string> */
|
/** @var list<string> */
|
||||||
return Arr::where($meta, static fn($meta): bool => is_string($meta))
|
return Arr::where($meta, static fn($meta): bool => is_string($meta))
|
||||||
|> (static fn(array $array) => Arr::map($array, genere_balise_img_multiformats(...)));
|
|> (static fn(array $array) => Arr::map($array, Resource::output_multi_formats_img_tag(...)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ namespace HaikuAtelier\WP;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
|
use function Crell\fp\pipe;
|
||||||
use function filemtime;
|
use function filemtime;
|
||||||
use function get_template_directory;
|
use function get_template_directory;
|
||||||
use function get_template_directory_uri;
|
use function get_template_directory_uri;
|
||||||
|
|
@ -29,12 +30,7 @@ final readonly class Resource {
|
||||||
|
|
||||||
$version = (string) $file_mtime;
|
$version = (string) $file_mtime;
|
||||||
|
|
||||||
wp_enqueue_script_module(
|
wp_enqueue_script_module(id: $id, src: $file_uri, deps: [], version: $version);
|
||||||
id: $id,
|
|
||||||
src: $file_uri,
|
|
||||||
deps: [],
|
|
||||||
version: $version,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -52,12 +48,74 @@ final readonly class Resource {
|
||||||
|
|
||||||
$ver = (string) $file_mtime;
|
$ver = (string) $file_mtime;
|
||||||
|
|
||||||
wp_enqueue_style(
|
wp_enqueue_style(handle: $handle, src: $file_uri, deps: [], ver: $ver, media: 'all');
|
||||||
handle: $handle,
|
}
|
||||||
src: $file_uri,
|
|
||||||
deps: [],
|
/**
|
||||||
ver: $ver,
|
* TODO.
|
||||||
media: 'all',
|
*
|
||||||
|
* @param string $id TODO
|
||||||
|
* @param bool $lazy TODO
|
||||||
|
*
|
||||||
|
* @return string TODO
|
||||||
|
*/
|
||||||
|
public static function output_multi_formats_img_tag(string $id, bool $lazy = false): string {
|
||||||
|
$int_id = (int) $id;
|
||||||
|
|
||||||
|
if (-1 === $int_id) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$url = wp_get_attachment_image_url($int_id, 'full');
|
||||||
|
$chemin = realpath(get_attached_file($int_id)) ?: realpath(get_attached_file($int_id));
|
||||||
|
$alt = get_post_meta($int_id, '_wp_attachment_image_alt', true);
|
||||||
|
$dimensions = $chemin ? getimagesize($chemin) : ['', ''];
|
||||||
|
|
||||||
|
$avif = $chemin ? realpath(pathinfo($chemin)['dirname'] . '/' . pathinfo($chemin)['filename'] . '.avif') : false;
|
||||||
|
$jxl = $chemin ? realpath(pathinfo($chemin)['dirname'] . '/' . pathinfo($chemin)['filename'] . '.jxl') : false;
|
||||||
|
|
||||||
|
// Génère un tableau avec les différents formats valides
|
||||||
|
$formats = pipe(
|
||||||
|
[$avif, $jxl],
|
||||||
|
static fn($tableau): array => array_filter(
|
||||||
|
array: $tableau,
|
||||||
|
callback: static fn($chemin_format): bool => false !== $chemin_format,
|
||||||
|
),
|
||||||
|
static fn($tableau): array => array_map(array: $tableau, callback: static fn($chemin_format): array => [
|
||||||
|
'format' => pathinfo((string) $chemin_format)['extension'],
|
||||||
|
'taille' => filesize($chemin_format),
|
||||||
|
'url' =>
|
||||||
|
pathinfo($url)['dirname']
|
||||||
|
. '/'
|
||||||
|
. pathinfo($url)['filename']
|
||||||
|
. '.'
|
||||||
|
. pathinfo((string) $chemin_format)['extension'],
|
||||||
|
]),
|
||||||
);
|
);
|
||||||
|
usort(array: $formats, callback: static fn($a, $b): int => $a['taille'] <=> $b['taille']);
|
||||||
|
|
||||||
|
// Construis les balises <source> avec les formats valides
|
||||||
|
$sources = '';
|
||||||
|
foreach ($formats as $format) {
|
||||||
|
$height = $dimensions[0];
|
||||||
|
$width = $dimensions[1];
|
||||||
|
$sources .= "<source height='{$height}' srcset='{$format['url']}' type='image/{$format['format']}' width='{$width}' />\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$loading = $lazy ? 'lazy' : 'eager';
|
||||||
|
|
||||||
|
return <<<EOD
|
||||||
|
{$sources}
|
||||||
|
|
||||||
|
<img
|
||||||
|
alt="{$alt}"
|
||||||
|
decoding="async"
|
||||||
|
height="{$dimensions[0]}"
|
||||||
|
loading="{$loading}"
|
||||||
|
onload="this.style.opacity=1"
|
||||||
|
src="{$url}"
|
||||||
|
width="{$dimensions[1]}"
|
||||||
|
/>
|
||||||
|
EOD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,19 @@ use function Psl\Option\none;
|
||||||
use function Psl\Option\some;
|
use function Psl\Option\some;
|
||||||
|
|
||||||
final readonly class Term {
|
final readonly class Term {
|
||||||
|
/**
|
||||||
|
* @return Option\Option<WP_Term>
|
||||||
|
*/
|
||||||
|
public static function get_term_by_id(int $id, string $taxonomy): Option\Option {
|
||||||
|
$term_data = get_term(term: $id, taxonomy: $taxonomy);
|
||||||
|
|
||||||
|
if ($term_data instanceof WP_Term) {
|
||||||
|
return some($term_data);
|
||||||
|
} else {
|
||||||
|
return none();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Option\Option<list<WP_Term>>
|
* @return Option\Option<list<WP_Term>>
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,34 @@
|
||||||
import { Option, pipe } from "effect";
|
import { Array as FxArray, Option, pipe } from "effect";
|
||||||
import { Array as FxArray } from "effect";
|
import type { NonEmptyReadonlyArray } from "effect/Array";
|
||||||
import { NonEmptyReadonlyArray } from "effect/Array";
|
|
||||||
import { getOptionOrThrowWithError } from "./utils";
|
import { getOptionOrThrowWithError } from "./utils.ts";
|
||||||
|
|
||||||
/** Type union des parents possibles pour un `querySelector`. */
|
/** Type union des parents possibles pour un `querySelector`. */
|
||||||
export type ParentElement = Document | Element;
|
type ParentElement = Document | Element;
|
||||||
|
|
||||||
export const getFirstSelectorFromParent =
|
const getFirstSelectorFromParent =
|
||||||
(parent: ParentElement) =>
|
(parent: ParentElement) =>
|
||||||
<E extends Element = Element>(selector: string): Option.Option<NonNullable<E>> =>
|
<E extends Element = Element>(selector: string): Option.Option<NonNullable<E>> =>
|
||||||
Option.fromNullishOr(parent.querySelector<E>(selector));
|
Option.fromNullishOr(parent.querySelector<E>(selector));
|
||||||
|
|
||||||
export const getFirstSelectorFromDocument = <E extends Element = Element>(
|
const getFirstSelectorFromParentOrThrow =
|
||||||
selector: string,
|
(parent: ParentElement) =>
|
||||||
): Option.Option<NonNullable<E>> => getFirstSelectorFromParent(document)<E>(selector);
|
<E extends Element = Element>(selector: string): NonNullable<E> =>
|
||||||
|
pipe(
|
||||||
|
getFirstSelectorFromParent(parent)<E>(selector),
|
||||||
|
getOptionOrThrowWithError(`Il n'y a pas d'Élément dans le parent avec le sélecteur suivant : ${selector}.`),
|
||||||
|
);
|
||||||
|
|
||||||
export const getFirstSelectorFromDocumentOrThrow = <E extends Element = Element>(selector: string): NonNullable<E> =>
|
const getFirstSelectorFromDocument = <E extends Element = Element>(selector: string): Option.Option<NonNullable<E>> =>
|
||||||
|
getFirstSelectorFromParent(document)<E>(selector);
|
||||||
|
|
||||||
|
const getFirstSelectorFromDocumentOrThrow = <E extends Element = Element>(selector: string): NonNullable<E> =>
|
||||||
pipe(
|
pipe(
|
||||||
getFirstSelectorFromDocument<E>(selector),
|
getFirstSelectorFromDocument<E>(selector),
|
||||||
getOptionOrThrowWithError(`Il n'y a pas d'Élément dans le Document avec le sélecteur suivant : ${selector}.`),
|
getOptionOrThrowWithError(`Il n'y a pas d'Élément dans le Document avec le sélecteur suivant : ${selector}.`),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getAllSelectorFromParent =
|
const getAllSelectorFromParent =
|
||||||
(parent: ParentElement) =>
|
(parent: ParentElement) =>
|
||||||
<E extends Element = Element>(selector: string): Option.Option<NonEmptyReadonlyArray<E>> =>
|
<E extends Element = Element>(selector: string): Option.Option<NonEmptyReadonlyArray<E>> =>
|
||||||
pipe(
|
pipe(
|
||||||
|
|
@ -31,14 +38,23 @@ export const getAllSelectorFromParent =
|
||||||
(xs: Array<E>) => Option.liftPredicate(FxArray.isReadonlyArrayNonEmpty)(xs),
|
(xs: Array<E>) => Option.liftPredicate(FxArray.isReadonlyArrayNonEmpty)(xs),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getAllSelectorFromDocument = <E extends Element = Element>(
|
const getAllSelectorFromDocument = <E extends Element = Element>(
|
||||||
selector: string,
|
selector: string,
|
||||||
): Option.Option<NonEmptyReadonlyArray<E>> => getAllSelectorFromParent(document)<E>(selector);
|
): Option.Option<NonEmptyReadonlyArray<E>> => getAllSelectorFromParent(document)<E>(selector);
|
||||||
|
|
||||||
export const getAllSelectorFromDocumentOrThrow = <E extends Element = Element>(
|
const getAllSelectorFromDocumentOrThrow = <E extends Element = Element>(selector: string): NonEmptyReadonlyArray<E> =>
|
||||||
selector: string,
|
|
||||||
): NonEmptyReadonlyArray<E> =>
|
|
||||||
pipe(
|
pipe(
|
||||||
getAllSelectorFromDocument<E>(selector),
|
getAllSelectorFromDocument<E>(selector),
|
||||||
getOptionOrThrowWithError(`Il n'y a pas d'Éléments dans le Document avec le sélecteur suivant : ${selector}.`),
|
getOptionOrThrowWithError(`Il n'y a pas d'Éléments dans le Document avec le sélecteur suivant : ${selector}.`),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export {
|
||||||
|
getAllSelectorFromDocument,
|
||||||
|
getAllSelectorFromDocumentOrThrow,
|
||||||
|
getAllSelectorFromParent,
|
||||||
|
getFirstSelectorFromDocument,
|
||||||
|
getFirstSelectorFromDocumentOrThrow,
|
||||||
|
getFirstSelectorFromParent,
|
||||||
|
getFirstSelectorFromParentOrThrow,
|
||||||
|
type ParentElement,
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -13,5 +13,5 @@ export const WCStoreCartAddItemArgsSchema = v.object({
|
||||||
/** Quantity of this item to add to the basket. */
|
/** Quantity of this item to add to the basket. */
|
||||||
quantity: v.optional(v.number()),
|
quantity: v.optional(v.number()),
|
||||||
/** Chosen attributes (for variations). */
|
/** Chosen attributes (for variations). */
|
||||||
variation: v.optional(v.array(WCStoreCartAddItemArgsItemsSchema)),
|
variation: v.pipe(v.optional(v.array(WCStoreCartAddItemArgsItemsSchema)), v.readonly()),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -7,42 +7,44 @@ import { match, P } from "ts-pattern";
|
||||||
import { ValiError } from "valibot";
|
import { ValiError } from "valibot";
|
||||||
import type { AnySchema } from "valibot";
|
import type { AnySchema } from "valibot";
|
||||||
|
|
||||||
import type { WCStoreBillingAddress, WCStoreShippingAddress } from "../lib/types/api/adresses";
|
import type { WCStoreBillingAddress, WCStoreShippingAddress } from "../lib/types/api/adresses.ts";
|
||||||
import type { WCStoreCart, WCStoreShippingRate, WCStoreShippingRateShippingRate } from "../lib/types/api/cart";
|
import type { WCStoreCart, WCStoreShippingRate, WCStoreShippingRateShippingRate } from "../lib/types/api/cart.ts";
|
||||||
import type { WCStoreCartUpdateCustomerArgs } from "../lib/types/api/cart-update-customer";
|
import type { WCStoreCartUpdateCustomerArgs } from "../lib/types/api/cart-update-customer.ts";
|
||||||
import type { WCV3Order, WCV3OrdersArgs } from "../lib/types/api/v3/orders";
|
import type { WCV3Order, WCV3OrdersArgs } from "../lib/types/api/v3/orders.ts";
|
||||||
import type { GenericPageState } from "../lib/types/pages";
|
import type { GenericPageState } from "../lib/types/pages.ts";
|
||||||
import type { FetchErrors, HttpCodeErrors } from "../lib/types/reseau";
|
import type { FetchErrors, HttpCodeErrors } from "../lib/types/reseau.ts";
|
||||||
|
|
||||||
import { ROUTE_API_MAJ_CLIENT, ROUTE_API_NOUVELLE_COMMANDES } from "../constantes/api";
|
import { ROUTE_API_MAJ_CLIENT, ROUTE_API_NOUVELLE_COMMANDES } from "../constantes/api.ts";
|
||||||
import { ATTRIBUT_CHARGEMENT, ATTRIBUT_LIVRAISON_VALIDEE } from "../constantes/dom";
|
import { ATTRIBUT_CHARGEMENT, ATTRIBUT_LIVRAISON_VALIDEE } from "../constantes/dom.ts";
|
||||||
import { NOM_CANAL_REVALIDATION_LIVRAISON } from "../constantes/messages";
|
import { NOM_CANAL_REVALIDATION_LIVRAISON } from "../constantes/messages.ts";
|
||||||
import {
|
import {
|
||||||
ERREUR_ADRESSE_GENERIQUE,
|
ERREUR_ADRESSE_GENERIQUE,
|
||||||
ERREUR_ADRESSE_MAUVAIS_CODE_POSTAL,
|
ERREUR_ADRESSE_MAUVAIS_CODE_POSTAL,
|
||||||
ERREUR_GENERIQUE_CREATION_COMMANDE,
|
ERREUR_GENERIQUE_CREATION_COMMANDE,
|
||||||
ERREUR_GENERIQUE_RESEAU,
|
ERREUR_GENERIQUE_RESEAU,
|
||||||
ERREUR_GENERIQUE_SOUMISSION_ADRESSES,
|
ERREUR_GENERIQUE_SOUMISSION_ADRESSES,
|
||||||
} from "../constantes/messages-utilisateur";
|
} from "../constantes/messages-utilisateur.ts";
|
||||||
import { estErreurFetch, estErreurHttp, setButtonLoadingState } from "../lib/dom";
|
import { estErreurFetch, estErreurHttp, setButtonLoadingState } from "../lib/dom.ts";
|
||||||
import { reporteEtJournaliseErreur } from "../lib/erreurs";
|
import { reporteEtJournaliseErreur } from "../lib/erreurs.ts";
|
||||||
import { ErreurAdresseInvalide } from "../lib/erreurs/adresses";
|
import { ErreurAdresseInvalide } from "../lib/erreurs/adresses.ts";
|
||||||
import {
|
import {
|
||||||
ADRESSES_MAJ_EVENT,
|
ADRESSES_MAJ_EVENT,
|
||||||
createUpdatedShippingRatesEvent,
|
createUpdatedShippingRatesEvent,
|
||||||
createUpdatedTotalsEvent,
|
createUpdatedTotalsEvent,
|
||||||
} from "../lib/evenements/panier";
|
} from "../lib/evenements/panier.ts";
|
||||||
import { emetUniqueMessageBroadcastChannel } from "../lib/messages";
|
import { emetUniqueMessageBroadcastChannel } from "../lib/messages.ts";
|
||||||
import { diviseParCent } from "../lib/nombres";
|
import { diviseParCent } from "../lib/nombres.ts";
|
||||||
import { newPartialResponse, prefilledPostBackend, safeFetch, traiteErreursBackendWooCommerce } from "../lib/reseau";
|
import { newPartialResponse, prefilledPostBackend, safeFetch, traiteErreursBackendWooCommerce } from "../lib/reseau.ts";
|
||||||
import { find, first } from "../lib/safe-arrays";
|
import { find, first } from "../lib/safe-arrays.ts";
|
||||||
import { WCStoreCartSchema } from "../lib/schemas/api/cart";
|
import { WCStoreCartSchema } from "../lib/schemas/api/cart.ts";
|
||||||
import { WCStoreCartUpdateCustomerArgsSchema } from "../lib/schemas/api/cart-update-customer";
|
import { WCStoreCartUpdateCustomerArgsSchema } from "../lib/schemas/api/cart-update-customer.ts";
|
||||||
import { estWCAddressError } from "../lib/schemas/api/erreurs";
|
import { estWCAddressError } from "../lib/schemas/api/erreurs.ts";
|
||||||
import { WCV3OrdersArgsSchema, WCV3OrderSchema } from "../lib/schemas/api/v3/orders";
|
import { WCV3OrdersArgsSchema, WCV3OrderSchema } from "../lib/schemas/api/v3/orders.ts";
|
||||||
import { safeSchemaParse } from "../lib/validation";
|
import { safeSchemaParse } from "../lib/validation.ts";
|
||||||
import { E } from "./scripts-page-panier-elements";
|
import { E } from "./scripts-page-panier-elements.ts";
|
||||||
import { getShippingRatesLS } from "./scripts-page-panier-local-storage";
|
import { getShippingRatesLS } from "./scripts-page-panier-local-storage.ts";
|
||||||
|
import { ReadonlyRecord } from "effect/Record";
|
||||||
|
import { Console, Effect, Stream } from "effect";
|
||||||
|
|
||||||
type Addresses = {
|
type Addresses = {
|
||||||
billing_address: WCStoreBillingAddress;
|
billing_address: WCStoreBillingAddress;
|
||||||
|
|
@ -50,23 +52,44 @@ type Addresses = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// @ts-expect-error -- États injectés par le modèle PHP
|
// @ts-expect-error -- États injectés par le modèle PHP
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- États injectés par le modèle PHP
|
|
||||||
const ETATS_PAGE: GenericPageState = _etats;
|
const ETATS_PAGE: GenericPageState = _etats;
|
||||||
const postBackend = prefilledPostBackend(ETATS_PAGE.nonce, ETATS_PAGE.authString);
|
const postBackend = prefilledPostBackend(ETATS_PAGE.nonce, ETATS_PAGE.authString);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialise les Émetteurs d'Événements sur divers parties du Panier.
|
* Initialise les Émetteurs d'Événements sur divers parties du Panier.
|
||||||
*
|
*
|
||||||
* @returns void
|
* @returns Un `Effect` ne retournant rien et ne pouvant échouer.
|
||||||
*/
|
*/
|
||||||
export const initCartFormEventEmitters = (): void => {
|
export const initCartFormEventEmitters = Effect.fn("initCartFormEventEmitters")(function* () {
|
||||||
E.FORMULAIRE_PANIER.addEventListener("change", (): void => {
|
return yield* pipe(
|
||||||
Maybe.fromFalsy(E.FORMULAIRE_PANIER.checkValidity()).ifJust((): boolean =>
|
Stream.fromEventListener(E.FORMULAIRE_PANIER, "change"),
|
||||||
window.dispatchEvent(ADRESSES_MAJ_EVENT),
|
Stream.tap((event: Event) => {
|
||||||
);
|
// La cible ne peut qu'être un Formulaire.
|
||||||
});
|
const target = event.target as HTMLFormElement;
|
||||||
};
|
|
||||||
|
|
||||||
export const getAddressesFromForm = (formFields: Record<string, string>, areAddressesMerged: boolean): Addresses => ({
|
if (target.checkValidity()) {
|
||||||
|
window.dispatchEvent(ADRESSES_MAJ_EVENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Effect.void;
|
||||||
|
}),
|
||||||
|
Stream.runDrain,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère les valeurs des adresses renseignées dans les Formulaires correspondants.
|
||||||
|
*
|
||||||
|
* @param formFields Les champs du Formulaire sous forme d'Objet.
|
||||||
|
* @param areAddressesMerged Est-ce que l'utilisateur utilise la même adresse pour livraison et facturation.
|
||||||
|
* @returns Les Adresses proprement renseignées.
|
||||||
|
*
|
||||||
|
* TODO: Utiliser un Schéma pour parser.
|
||||||
|
*/
|
||||||
|
export const getAddressesFromForm = (
|
||||||
|
formFields: ReadonlyRecord<string, string>,
|
||||||
|
areAddressesMerged: boolean,
|
||||||
|
): Addresses => ({
|
||||||
billing_address: {
|
billing_address: {
|
||||||
address_1: formFields["facturation-adresse"] ?? formFields["livraison-adresse"] ?? "",
|
address_1: formFields["facturation-adresse"] ?? formFields["livraison-adresse"] ?? "",
|
||||||
address_2: "",
|
address_2: "",
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,13 @@ import { match, P } from "ts-pattern";
|
||||||
import { ValiError } from "valibot";
|
import { ValiError } from "valibot";
|
||||||
import type { AnySchema } from "valibot";
|
import type { AnySchema } from "valibot";
|
||||||
|
|
||||||
import type { WCStoreCart } from "../lib/types/api/cart";
|
import type { WCStoreCart } from "../lib/types/api/cart.ts";
|
||||||
import type { WCStoreCartRemoveItemArgs } from "../lib/types/api/cart-remove-item";
|
import type { WCStoreCartRemoveItemArgs } from "../lib/types/api/cart-remove-item.ts";
|
||||||
import type { WCStoreCartUpdateItemArgs } from "../lib/types/api/cart-update-item";
|
import type { WCStoreCartUpdateItemArgs } from "../lib/types/api/cart-update-item.ts";
|
||||||
import type { GenericPageState } from "../lib/types/pages";
|
import type { GenericPageState } from "../lib/types/pages.ts";
|
||||||
import type { FetchErrors, HttpCodeErrors } from "../lib/types/reseau";
|
import type { FetchErrors, HttpCodeErrors } from "../lib/types/reseau.ts";
|
||||||
|
|
||||||
import { ROUTE_API_MAJ_ARTICLE_PANIER, ROUTE_API_RETIRE_ARTICLE_PANIER } from "../constantes/api";
|
import { ROUTE_API_MAJ_ARTICLE_PANIER, ROUTE_API_RETIRE_ARTICLE_PANIER } from "../constantes/api.ts";
|
||||||
import {
|
import {
|
||||||
ATTRIBUT_CLE_PANIER,
|
ATTRIBUT_CLE_PANIER,
|
||||||
ATTRIBUT_DESACTIVE,
|
ATTRIBUT_DESACTIVE,
|
||||||
|
|
@ -21,25 +21,24 @@ import {
|
||||||
DOM_BOUTON_SOUSTRACTION_QUANTITE,
|
DOM_BOUTON_SOUSTRACTION_QUANTITE,
|
||||||
DOM_BOUTON_SUPPRESSION_PANIER,
|
DOM_BOUTON_SUPPRESSION_PANIER,
|
||||||
DOM_CHAMP_QUANTITE_LIGNE_PANIER,
|
DOM_CHAMP_QUANTITE_LIGNE_PANIER,
|
||||||
} from "../constantes/dom";
|
} from "../constantes/dom.ts";
|
||||||
import { NOM_CANAL_REVALIDATION_LIVRAISON } from "../constantes/messages";
|
import { NOM_CANAL_REVALIDATION_LIVRAISON } from "../constantes/messages.ts";
|
||||||
import { mustGetEleInParent } from "../lib/dom";
|
import { BadRequestError, reporteErreur, ServerError } from "../lib/erreurs.ts";
|
||||||
import { BadRequestError, reporteErreur, ServerError } from "../lib/erreurs";
|
|
||||||
import {
|
import {
|
||||||
emetMessageMajBoutonPanier,
|
emetMessageMajBoutonPanier,
|
||||||
emetMessageMajContenuPanier,
|
emetMessageMajContenuPanier,
|
||||||
emetUniqueMessageBroadcastChannel,
|
emetUniqueMessageBroadcastChannel,
|
||||||
} from "../lib/messages";
|
} from "../lib/messages.ts";
|
||||||
import { diviseParCent } from "../lib/nombres";
|
import { diviseParCent } from "../lib/nombres.ts";
|
||||||
import { newPartialResponse, postBackend, safeFetch, traiteErreursBackendWooCommerce } from "../lib/reseau";
|
import { newPartialResponse, postBackend, safeFetch, traiteErreursBackendWooCommerce } from "../lib/reseau.ts";
|
||||||
import { WCStoreCartSchema } from "../lib/schemas/api/cart";
|
import { WCStoreCartSchema } from "../lib/schemas/api/cart.ts";
|
||||||
import { WCStoreCartRemoveItemArgsSchema } from "../lib/schemas/api/cart-remove-item";
|
import { WCStoreCartRemoveItemArgsSchema } from "../lib/schemas/api/cart-remove-item.ts";
|
||||||
import { WCStoreCartUpdateItemArgsSchema } from "../lib/schemas/api/cart-update-item";
|
import { WCStoreCartUpdateItemArgsSchema } from "../lib/schemas/api/cart-update-item.ts";
|
||||||
import { safeSchemaParse } from "../lib/validation";
|
import { safeSchemaParse } from "../lib/validation.ts";
|
||||||
import { E } from "./scripts-page-panier-elements";
|
import { E } from "./scripts-page-panier-elements.ts";
|
||||||
|
import { getFirstSelectorFromParentOrThrow } from "../../scripts-effect/lib/dom.ts";
|
||||||
|
|
||||||
// @ts-expect-error -- États injectés par le modèle PHP
|
// @ts-expect-error -- États injectés par le modèle PHP
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- États injectés par le modèle PHP
|
|
||||||
const PAGE_STATE: GenericPageState = _etats;
|
const PAGE_STATE: GenericPageState = _etats;
|
||||||
|
|
||||||
type CartEntryInteractiveElements = {
|
type CartEntryInteractiveElements = {
|
||||||
|
|
@ -49,31 +48,35 @@ type CartEntryInteractiveElements = {
|
||||||
substractionButton: HTMLButtonElement;
|
substractionButton: HTMLButtonElement;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getCartEntryInteractiveEles = (entree: HTMLElement): CartEntryInteractiveElements => {
|
const getCartEntryInteractiveEles = (entry: HTMLElement): CartEntryInteractiveElements => {
|
||||||
const mustGetEle = mustGetEleInParent(entree);
|
const entrySelector = getFirstSelectorFromParentOrThrow(entry);
|
||||||
return {
|
return {
|
||||||
additionButton: mustGetEle<HTMLButtonElement>(DOM_BOUTON_ADDITION_QUANTITE),
|
additionButton: entrySelector<HTMLButtonElement>(DOM_BOUTON_ADDITION_QUANTITE),
|
||||||
deletionButton: mustGetEle<HTMLButtonElement>(DOM_BOUTON_SUPPRESSION_PANIER),
|
deletionButton: entrySelector<HTMLButtonElement>(DOM_BOUTON_SUPPRESSION_PANIER),
|
||||||
quantityInput: mustGetEle<HTMLInputElement>(DOM_CHAMP_QUANTITE_LIGNE_PANIER),
|
quantityInput: entrySelector<HTMLInputElement>(DOM_CHAMP_QUANTITE_LIGNE_PANIER),
|
||||||
substractionButton: mustGetEle<HTMLButtonElement>(DOM_BOUTON_SOUSTRACTION_QUANTITE),
|
substractionButton: entrySelector<HTMLButtonElement>(DOM_BOUTON_SOUSTRACTION_QUANTITE),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Met à jour l'état d'activation des Boutons d'action sur chaque Entrée du Panier.
|
* Met à jour l'état d'activation des Boutons d'action pour toutes les Entrées du Panier.
|
||||||
|
|
||||||
* @param activated Le nouvel état d'activation (activé/désactivé).
|
* @param activated Le nouvel état d'activation (activé/désactivé).
|
||||||
* @returns Rien.
|
* @returns Rien.
|
||||||
*/
|
*/
|
||||||
export const toggleCartEntryButtons =
|
const toggleCartEntryButtons =
|
||||||
(activated: boolean) =>
|
(activated: boolean) =>
|
||||||
(cartEntries: ReadonlyArray<CartEntryInteractiveElements>): void =>
|
(cartEntries: ReadonlyArray<CartEntryInteractiveElements>): void => {
|
||||||
arrayForEach(cartEntries, (e: CartEntryInteractiveElements): void => {
|
arrayForEach(cartEntries, (e: CartEntryInteractiveElements): void => {
|
||||||
if (activated) {
|
if (activated) {
|
||||||
// Active les Boutons
|
// Active les Boutons
|
||||||
Number(e.quantityInput.value) === 1
|
const entryQuantity = Number(e.quantityInput.value);
|
||||||
? e.substractionButton.setAttribute(ATTRIBUT_DESACTIVE, "")
|
// Empêche la réducation de la quantité si on se trouve au minimum.
|
||||||
: e.substractionButton.removeAttribute(ATTRIBUT_DESACTIVE);
|
if (entryQuantity === 1) {
|
||||||
|
e.substractionButton.setAttribute(ATTRIBUT_DESACTIVE, "");
|
||||||
|
} else {
|
||||||
|
e.substractionButton.removeAttribute(ATTRIBUT_DESACTIVE);
|
||||||
|
}
|
||||||
e.additionButton.removeAttribute(ATTRIBUT_DESACTIVE);
|
e.additionButton.removeAttribute(ATTRIBUT_DESACTIVE);
|
||||||
e.deletionButton.removeAttribute(ATTRIBUT_DESACTIVE);
|
e.deletionButton.removeAttribute(ATTRIBUT_DESACTIVE);
|
||||||
e.deletionButton.textContent = "Remove";
|
e.deletionButton.textContent = "Remove";
|
||||||
|
|
@ -85,22 +88,29 @@ export const toggleCartEntryButtons =
|
||||||
e.deletionButton.textContent = "Loading";
|
e.deletionButton.textContent = "Loading";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const initialiseActionsEntreesPanier = (): void => {
|
const initActionsOnCartEntries = (): void => {
|
||||||
// Initialise des actions uniquement si des Entrées dans le Panier existent
|
// Initialise des actions uniquement si des Entrées dans le Panier existent
|
||||||
E.ENTREES_PANIER.ifRight((cartEntries: Array<HTMLElement>) =>
|
E.ENTREES_PANIER.ifRight((cartEntries: Array<HTMLElement>) => {
|
||||||
arrayForEach(cartEntries, (entry: HTMLElement): void => {
|
arrayForEach(cartEntries, (entry: HTMLElement): void => {
|
||||||
// Retire l'entrée du DOM si la clé Panier n'existe pas puis arrête précocement
|
// Retire l'entrée du DOM si la clé Panier n'existe pas puis arrête précocement
|
||||||
const entryKey: string = Maybe.fromNullable(entry.getAttribute(ATTRIBUT_CLE_PANIER))
|
const entryKey: string = Maybe.fromNullable(entry.getAttribute(ATTRIBUT_CLE_PANIER))
|
||||||
.ifNothing(() => entry.remove())
|
.ifNothing(() => {
|
||||||
|
entry.remove();
|
||||||
|
})
|
||||||
.orDefault("CLE_PANIER_INEXISTANTE");
|
.orDefault("CLE_PANIER_INEXISTANTE");
|
||||||
const entryButtons: CartEntryInteractiveElements = getCartEntryInteractiveEles(entry);
|
const entryButtons: CartEntryInteractiveElements = getCartEntryInteractiveEles(entry);
|
||||||
|
|
||||||
entry.addEventListener("click", (event: Event): void => {
|
entry.addEventListener("click", (event: Event): void => {
|
||||||
// Discrimine en fonction de l'Élément cliqué (délégation d'Événements)
|
// Discrimine en fonction de l'Élément cliqué (délégation d'Événements)
|
||||||
match(event.target)
|
match(event.target)
|
||||||
// Cas impossible
|
[
|
||||||
.with(P.nullish, () => console.error(event.target))
|
// Cas impossible
|
||||||
|
"with"
|
||||||
|
](P.nullish, () => {
|
||||||
|
console.error(event.target);
|
||||||
|
})
|
||||||
// Clic sur le Bouton d'addition
|
// Clic sur le Bouton d'addition
|
||||||
.when(
|
.when(
|
||||||
(target: EventTarget) => (target as HTMLElement).matches(DOM_BOUTON_ADDITION_QUANTITE),
|
(target: EventTarget) => (target as HTMLElement).matches(DOM_BOUTON_ADDITION_QUANTITE),
|
||||||
|
|
@ -116,7 +126,9 @@ export const initialiseActionsEntreesPanier = (): void => {
|
||||||
safeSchemaParse({ key: entryKey, quantity: q + 1 }, WCStoreCartUpdateItemArgsSchema),
|
safeSchemaParse({ key: entryKey, quantity: q + 1 }, WCStoreCartUpdateItemArgsSchema),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.ifRight(() => pipe(cartEntries, arrayMap(getCartEntryInteractiveEles), toggleCartEntryButtons(false)))
|
.ifRight(() => {
|
||||||
|
pipe(cartEntries, arrayMap(getCartEntryInteractiveEles), toggleCartEntryButtons(false));
|
||||||
|
})
|
||||||
.chain((args: WCStoreCartUpdateItemArgs) =>
|
.chain((args: WCStoreCartUpdateItemArgs) =>
|
||||||
safeFetch(
|
safeFetch(
|
||||||
postBackend({
|
postBackend({
|
||||||
|
|
@ -129,7 +141,7 @@ export const initialiseActionsEntreesPanier = (): void => {
|
||||||
.chain((r: Response) =>
|
.chain((r: Response) =>
|
||||||
EitherAsync<ServerError, unknown>(async ({ throwE }) =>
|
EitherAsync<ServerError, unknown>(async ({ throwE }) =>
|
||||||
match(await newPartialResponse(r))
|
match(await newPartialResponse(r))
|
||||||
.with({ status: 200 }, (r) => r.body)
|
["with"]({ status: 200 }, (r) => r.body)
|
||||||
.otherwise((rs): never => throwE(traiteErreursBackendWooCommerce(rs))),
|
.otherwise((rs): never => throwE(traiteErreursBackendWooCommerce(rs))),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -149,24 +161,24 @@ export const initialiseActionsEntreesPanier = (): void => {
|
||||||
})
|
})
|
||||||
.ifLeft((err: FetchErrors | HttpCodeErrors | ValiError<AnySchema>): void => {
|
.ifLeft((err: FetchErrors | HttpCodeErrors | ValiError<AnySchema>): void => {
|
||||||
match(err)
|
match(err)
|
||||||
.with(P.instanceOf(ValiError), (e) => {
|
["with"](P.instanceOf(ValiError), (e) => {
|
||||||
reporteErreur(e);
|
reporteErreur(e);
|
||||||
console.error(e.issues);
|
console.error(e.issues);
|
||||||
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
|
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
|
||||||
})
|
})
|
||||||
.with(P.instanceOf(ServerError), P.instanceOf(BadRequestError), (e) => {
|
["with"](P.instanceOf(ServerError), P.instanceOf(BadRequestError), (e) => {
|
||||||
reporteErreur(e);
|
reporteErreur(e);
|
||||||
console.error(e);
|
console.error(e);
|
||||||
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
|
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
|
||||||
})
|
})
|
||||||
.with(P.instanceOf(DOMException), P.instanceOf(TypeError), P.instanceOf(Error), (e) => {
|
["with"](P.instanceOf(DOMException), P.instanceOf(TypeError), P.instanceOf(Error), (e) => {
|
||||||
reporteErreur(e);
|
reporteErreur(e);
|
||||||
console.error(e);
|
console.error(e);
|
||||||
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_RESEAU;
|
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_RESEAU;
|
||||||
})
|
})
|
||||||
.exhaustive();
|
.exhaustive();
|
||||||
})
|
})
|
||||||
.finally(() => {
|
["finally"](() => {
|
||||||
pipe(cartEntries, arrayMap(getCartEntryInteractiveEles), toggleCartEntryButtons(true));
|
pipe(cartEntries, arrayMap(getCartEntryInteractiveEles), toggleCartEntryButtons(true));
|
||||||
})
|
})
|
||||||
.run();
|
.run();
|
||||||
|
|
@ -188,9 +200,9 @@ export const initialiseActionsEntreesPanier = (): void => {
|
||||||
safeSchemaParse({ key: entryKey, quantity: valeur - 1 }, WCStoreCartUpdateItemArgsSchema),
|
safeSchemaParse({ key: entryKey, quantity: valeur - 1 }, WCStoreCartUpdateItemArgsSchema),
|
||||||
)
|
)
|
||||||
// 2. Exécute un Effet pour empêcher les requêtes concurrentes
|
// 2. Exécute un Effet pour empêcher les requêtes concurrentes
|
||||||
.ifRight(() =>
|
.ifRight(() => {
|
||||||
pipe(cartEntries, arrayMap(getCartEntryInteractiveEles), toggleCartEntryButtons(false)),
|
pipe(cartEntries, arrayMap(getCartEntryInteractiveEles), toggleCartEntryButtons(false));
|
||||||
)
|
})
|
||||||
// 3. Exécute la requête via fetch sous forme d'EitherAsync
|
// 3. Exécute la requête via fetch sous forme d'EitherAsync
|
||||||
.chain((args: WCStoreCartUpdateItemArgs) =>
|
.chain((args: WCStoreCartUpdateItemArgs) =>
|
||||||
safeFetch(
|
safeFetch(
|
||||||
|
|
@ -206,9 +218,9 @@ export const initialiseActionsEntreesPanier = (): void => {
|
||||||
EitherAsync<BadRequestError | Error | ServerError, unknown>(async ({ throwE }) =>
|
EitherAsync<BadRequestError | Error | ServerError, unknown>(async ({ throwE }) =>
|
||||||
// Simplifie les données à matcher
|
// Simplifie les données à matcher
|
||||||
match(await newPartialResponse(reponse))
|
match(await newPartialResponse(reponse))
|
||||||
.with({ status: 500 }, () => throwE(new ServerError("500 Server Error")))
|
["with"]({ status: 500 }, () => throwE(new ServerError("500 Server Error")))
|
||||||
.with({ status: 400 }, () => throwE(new BadRequestError("400 Bad Request Error")))
|
["with"]({ status: 400 }, () => throwE(new BadRequestError("400 Bad Request Error")))
|
||||||
.with({ status: 200 }, (r) => r.body)
|
["with"]({ status: 200 }, (r) => r.body)
|
||||||
.otherwise((erreur) => throwE(new Error(`Erreur inconnue ${String(erreur.status)}`))),
|
.otherwise((erreur) => throwE(new Error(`Erreur inconnue ${String(erreur.status)}`))),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -231,24 +243,24 @@ export const initialiseActionsEntreesPanier = (): void => {
|
||||||
// 7. Traite les Erreurs et affiche un message à l'Utilisateur
|
// 7. Traite les Erreurs et affiche un message à l'Utilisateur
|
||||||
.ifLeft((erreur: BadRequestError | FetchErrors | ServerError | ValiError<AnySchema>): void => {
|
.ifLeft((erreur: BadRequestError | FetchErrors | ServerError | ValiError<AnySchema>): void => {
|
||||||
match(erreur)
|
match(erreur)
|
||||||
.with(P.instanceOf(ValiError), (e) => {
|
["with"](P.instanceOf(ValiError), (e) => {
|
||||||
reporteErreur(e);
|
reporteErreur(e);
|
||||||
console.error(e.issues);
|
console.error(e.issues);
|
||||||
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
|
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
|
||||||
})
|
})
|
||||||
.with(P.instanceOf(ServerError), P.instanceOf(BadRequestError), (e) => {
|
["with"](P.instanceOf(ServerError), P.instanceOf(BadRequestError), (e) => {
|
||||||
reporteErreur(e);
|
reporteErreur(e);
|
||||||
console.error(e);
|
console.error(e);
|
||||||
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
|
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
|
||||||
})
|
})
|
||||||
.with(P.instanceOf(DOMException), P.instanceOf(TypeError), P.instanceOf(Error), (e) => {
|
["with"](P.instanceOf(DOMException), P.instanceOf(TypeError), P.instanceOf(Error), (e) => {
|
||||||
reporteErreur(e);
|
reporteErreur(e);
|
||||||
console.error(e);
|
console.error(e);
|
||||||
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_RESEAU;
|
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_RESEAU;
|
||||||
})
|
})
|
||||||
.exhaustive();
|
.exhaustive();
|
||||||
})
|
})
|
||||||
.finally(() => {
|
["finally"](() => {
|
||||||
// Réactive les Boutons
|
// Réactive les Boutons
|
||||||
pipe(cartEntries, arrayMap(getCartEntryInteractiveEles), toggleCartEntryButtons(true));
|
pipe(cartEntries, arrayMap(getCartEntryInteractiveEles), toggleCartEntryButtons(true));
|
||||||
})
|
})
|
||||||
|
|
@ -269,9 +281,9 @@ export const initialiseActionsEntreesPanier = (): void => {
|
||||||
// 1. Valide les Arguments de la Requête
|
// 1. Valide les Arguments de la Requête
|
||||||
.liftEither(safeSchemaParse({ key: entryKey }, WCStoreCartRemoveItemArgsSchema))
|
.liftEither(safeSchemaParse({ key: entryKey }, WCStoreCartRemoveItemArgsSchema))
|
||||||
// 2. Exécute un Effet pour empêcher les requêtes concurrentes
|
// 2. Exécute un Effet pour empêcher les requêtes concurrentes
|
||||||
.ifRight(() =>
|
.ifRight(() => {
|
||||||
pipe(cartEntries, arrayMap(getCartEntryInteractiveEles), toggleCartEntryButtons(false)),
|
pipe(cartEntries, arrayMap(getCartEntryInteractiveEles), toggleCartEntryButtons(false));
|
||||||
)
|
})
|
||||||
// 3. Exécute la requête via fetch sous forme d'EitherAsync
|
// 3. Exécute la requête via fetch sous forme d'EitherAsync
|
||||||
.chain((args: WCStoreCartRemoveItemArgs) =>
|
.chain((args: WCStoreCartRemoveItemArgs) =>
|
||||||
safeFetch(
|
safeFetch(
|
||||||
|
|
@ -287,9 +299,9 @@ export const initialiseActionsEntreesPanier = (): void => {
|
||||||
EitherAsync<BadRequestError | Error | ServerError, unknown>(async ({ throwE }) =>
|
EitherAsync<BadRequestError | Error | ServerError, unknown>(async ({ throwE }) =>
|
||||||
// Simplifie les données à matcher
|
// Simplifie les données à matcher
|
||||||
match(await newPartialResponse(reponse))
|
match(await newPartialResponse(reponse))
|
||||||
.with({ status: 500 }, () => throwE(new ServerError("500 Server Error")))
|
["with"]({ status: 500 }, () => throwE(new ServerError("500 Server Error")))
|
||||||
.with({ status: 400 }, () => throwE(new BadRequestError("400 Bad Request Error")))
|
["with"]({ status: 400 }, () => throwE(new BadRequestError("400 Bad Request Error")))
|
||||||
.with({ status: 200 }, (r) => r.body)
|
["with"]({ status: 200 }, (r) => r.body)
|
||||||
.otherwise((erreur) => throwE(new Error(`Erreur inconnue ${String(erreur.status)}`))),
|
.otherwise((erreur) => throwE(new Error(`Erreur inconnue ${String(erreur.status)}`))),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -315,24 +327,24 @@ export const initialiseActionsEntreesPanier = (): void => {
|
||||||
// 7. Traite les Erreurs et affiche un message à l'Utilisateur
|
// 7. Traite les Erreurs et affiche un message à l'Utilisateur
|
||||||
.ifLeft((erreur: BadRequestError | FetchErrors | ServerError | ValiError<AnySchema>): void => {
|
.ifLeft((erreur: BadRequestError | FetchErrors | ServerError | ValiError<AnySchema>): void => {
|
||||||
match(erreur)
|
match(erreur)
|
||||||
.with(P.instanceOf(ValiError), (e) => {
|
["with"](P.instanceOf(ValiError), (e) => {
|
||||||
reporteErreur(e);
|
reporteErreur(e);
|
||||||
console.error(e.issues);
|
console.error(e.issues);
|
||||||
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
|
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
|
||||||
})
|
})
|
||||||
.with(P.instanceOf(ServerError), P.instanceOf(BadRequestError), (e) => {
|
["with"](P.instanceOf(ServerError), P.instanceOf(BadRequestError), (e) => {
|
||||||
reporteErreur(e);
|
reporteErreur(e);
|
||||||
console.error(e);
|
console.error(e);
|
||||||
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
|
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
|
||||||
})
|
})
|
||||||
.with(P.instanceOf(DOMException), P.instanceOf(TypeError), P.instanceOf(Error), (e) => {
|
["with"](P.instanceOf(DOMException), P.instanceOf(TypeError), P.instanceOf(Error), (e) => {
|
||||||
reporteErreur(e);
|
reporteErreur(e);
|
||||||
console.error(e);
|
console.error(e);
|
||||||
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_RESEAU;
|
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_RESEAU;
|
||||||
})
|
})
|
||||||
.exhaustive();
|
.exhaustive();
|
||||||
})
|
})
|
||||||
.finally(() => {
|
["finally"](() => {
|
||||||
// Réactive les Boutons
|
// Réactive les Boutons
|
||||||
pipe(cartEntries, arrayMap(getCartEntryInteractiveEles), toggleCartEntryButtons(true));
|
pipe(cartEntries, arrayMap(getCartEntryInteractiveEles), toggleCartEntryButtons(true));
|
||||||
})
|
})
|
||||||
|
|
@ -342,6 +354,8 @@ export const initialiseActionsEntreesPanier = (): void => {
|
||||||
)
|
)
|
||||||
.otherwise((_) => {});
|
.otherwise((_) => {});
|
||||||
});
|
});
|
||||||
}),
|
});
|
||||||
);
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export { toggleCartEntryButtons, initActionsOnCartEntries as initialiseActionsEntreesPanier };
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ import { E } from "./page-panier/scripts-page-panier-elements.ts";
|
||||||
import { souscrisEvenementsPanier } from "./page-panier/scripts-page-panier-evenement.ts";
|
import { souscrisEvenementsPanier } from "./page-panier/scripts-page-panier-evenement.ts";
|
||||||
import { initShippingRatesChoicesActions } from "./page-panier/scripts-page-panier-methodes-livraison.ts";
|
import { initShippingRatesChoicesActions } from "./page-panier/scripts-page-panier-methodes-livraison.ts";
|
||||||
import { initialiseActionsEntreesPanier } from "./page-panier/scripts-page-panier-panneau-produits.ts";
|
import { initialiseActionsEntreesPanier } from "./page-panier/scripts-page-panier-panneau-produits.ts";
|
||||||
|
import { Effect } from "effect";
|
||||||
|
|
||||||
type ElementsEntreePanier = {
|
type ElementsEntreePanier = {
|
||||||
boutonAddition: HTMLButtonElement;
|
boutonAddition: HTMLButtonElement;
|
||||||
|
|
@ -176,7 +177,7 @@ const initialiseMajFormulairesPanier = (): void => {
|
||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", (): void => {
|
document.addEventListener("DOMContentLoaded", (): void => {
|
||||||
initCartFormEventEmitters();
|
Effect.runFork(initCartFormEventEmitters());
|
||||||
souscrisEvenementsPanier();
|
souscrisEvenementsPanier();
|
||||||
initialiseActionsEntreesPanier();
|
initialiseActionsEntreesPanier();
|
||||||
initShippingRatesChoicesActions();
|
initShippingRatesChoicesActions();
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import { match, P } from "ts-pattern";
|
||||||
import { ValiError } from "valibot";
|
import { ValiError } from "valibot";
|
||||||
import type { AnySchema } from "valibot";
|
import type { AnySchema } from "valibot";
|
||||||
|
|
||||||
import type { WCStoreCart } from "./lib/types/api/cart";
|
import type { WCStoreCart } from "./lib/types/api/cart.ts";
|
||||||
import type { WCStoreCartAddItemArgs, WCStoreCartAddItemArgsItems } from "./lib/types/api/cart-add-item.ts";
|
import type { WCStoreCartAddItemArgs, WCStoreCartAddItemArgsItems } from "./lib/types/api/cart-add-item.ts";
|
||||||
import type { FetchErrors } from "./lib/types/reseau.ts";
|
import type { FetchErrors } from "./lib/types/reseau.ts";
|
||||||
|
|
||||||
|
|
@ -39,6 +39,7 @@ import { WCStoreCartSchema } from "./lib/schemas/api/cart.ts";
|
||||||
import { safeSchemaParse } from "./lib/validation";
|
import { safeSchemaParse } from "./lib/validation";
|
||||||
|
|
||||||
type EnsembleLienContenu = [HTMLAnchorElement, HTMLElement];
|
type EnsembleLienContenu = [HTMLAnchorElement, HTMLElement];
|
||||||
|
|
||||||
/** États utiles pour les scripts de la page. */
|
/** États utiles pour les scripts de la page. */
|
||||||
type EtatsPage = {
|
type EtatsPage = {
|
||||||
/** L'ID en base de données du Produit. */
|
/** L'ID en base de données du Produit. */
|
||||||
|
|
@ -48,7 +49,6 @@ type EtatsPage = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// @ts-expect-error -- États injectés par le modèle PHP
|
// @ts-expect-error -- États injectés par le modèle PHP
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- États injectés par le modèle PHP
|
|
||||||
const ETATS_PAGE: EtatsPage = _etats;
|
const ETATS_PAGE: EtatsPage = _etats;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -149,18 +149,18 @@ const getAttributesFromDom = (): ReadonlyArray<WCStoreCartAddItemArgsItems> => {
|
||||||
return attributes;
|
return attributes;
|
||||||
};
|
};
|
||||||
|
|
||||||
function areArraysEqual<T>(array1: Array<T>, array2: Array<T>): boolean {
|
const areArraysEqual = <T>(array1: Array<T>, array2: Array<T>): boolean => {
|
||||||
if (array1 !== array2) {
|
if (array1 !== array2) {
|
||||||
const a1 = JSON.stringify(array1.toSorted());
|
const a1 = JSON.stringify(array1.toSorted());
|
||||||
const a2 = JSON.stringify(array2.toSorted());
|
const a2 = JSON.stringify(array2.toSorted());
|
||||||
return a1 === a2;
|
return a1 === a2;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
};
|
||||||
|
|
||||||
const updatePriceOnAttributeChange = (): void => {
|
const updatePriceOnAttributeChange = (): void => {
|
||||||
E.VARIATION_CHOICE_FORM.addEventListener("change", (): void => {
|
E.VARIATION_CHOICE_FORM.addEventListener("change", (): void => {
|
||||||
if (!E.VARIATION_CHOICE_FORM.checkValidity()) {
|
if (E.VARIATION_CHOICE_FORM.checkValidity() === false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,9 +183,8 @@ const ajouteProduitAuPanier = (event: MouseEvent): void => {
|
||||||
id: E.DOM_VARIATION.map((selecteur: HTMLSelectElement): number => Number(selecteur.value))
|
id: E.DOM_VARIATION.map((selecteur: HTMLSelectElement): number => Number(selecteur.value))
|
||||||
// Récupère l'ID du Produit de la Page pour les Produits simples
|
// Récupère l'ID du Produit de la Page pour les Produits simples
|
||||||
.orDefault(ETATS_PAGE.idProduit),
|
.orDefault(ETATS_PAGE.idProduit),
|
||||||
// Id: ETATS_PAGE.idProduit,
|
|
||||||
quantity: 1,
|
quantity: 1,
|
||||||
// Variation: getAttributeValuesFromDom(),
|
variation: getAttributesFromDom(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Réalise la Requête et traite sa Réponse
|
// Réalise la Requête et traite sa Réponse
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,10 @@ $products = wc_get_products([
|
||||||
assert(is_array($products), 'Les Produits de la Catégorie doivent être un tableau.');
|
assert(is_array($products), 'Les Produits de la Catégorie doivent être un tableau.');
|
||||||
return $products;
|
return $products;
|
||||||
}
|
}
|
||||||
|> (static fn(/** @var list<WC_Product> */ array $products): array => Arr::map($products, Product::new(...)));
|
|> (static fn(/** @var list<WC_Product> */ array $products): array => Arr::map(
|
||||||
|
$products,
|
||||||
|
Product::from_wc_product(...),
|
||||||
|
));
|
||||||
|
|
||||||
$context['products'] = $products;
|
$context['products'] = $products;
|
||||||
$context['category_id'] = $current_term->term_id;
|
$context['category_id'] = $current_term->term_id;
|
||||||
|
|
@ -60,7 +63,4 @@ add_action('wp_enqueue_scripts', function (): void {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Rendu
|
// Rendu
|
||||||
Timber::render(
|
Timber::render(filenames: $templates, data: $context);
|
||||||
filenames: $templates,
|
|
||||||
data: $context,
|
|
||||||
);
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,4 @@ $email = [
|
||||||
|
|
||||||
$context['commande'] = $email;
|
$context['commande'] = $email;
|
||||||
// Rendu
|
// Rendu
|
||||||
Timber::render(
|
Timber::render(filenames: $templates, data: $context);
|
||||||
filenames: $templates,
|
|
||||||
data: $context,
|
|
||||||
);
|
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,4 @@ $email['adresses']['facturation']['country'] = WC()->countries->countries[$comma
|
||||||
|
|
||||||
$context['commande'] = $email;
|
$context['commande'] = $email;
|
||||||
// Rendu
|
// Rendu
|
||||||
Timber::render(
|
Timber::render(filenames: $templates, data: $context);
|
||||||
filenames: $templates,
|
|
||||||
data: $context,
|
|
||||||
);
|
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,4 @@ $email['adresses']['facturation']['country'] = WC()->countries->countries[$comma
|
||||||
$context['commande'] = $email;
|
$context['commande'] = $email;
|
||||||
|
|
||||||
// Rendu
|
// Rendu
|
||||||
Timber::render(
|
Timber::render(filenames: $templates, data: $context);
|
||||||
filenames: $templates,
|
|
||||||
data: $context,
|
|
||||||
);
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue