@valentia-ai-skills/framework 1.0.12 → 1.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/skills/global/aisupportapp-project-architecture/SKILL.md +194 -0
- package/skills/global/aisupportapp-project-conventions/SKILL.md +202 -0
- package/skills/global/aisupportapp-project-workflows/SKILL.md +230 -0
- package/skills/global/aisupportapp-test-installation/SKILL.md +32 -0
- package/skills/global/api-design/SKILL.md +1 -1
- package/skills/global/appointment-oas-app/SKILL.md +169 -0
- package/skills/global/code-standards/SKILL.md +1 -1
- package/skills/global/project-scanner/SKILL.md +1 -1
- package/skills/global/viteapp-core-workflows/SKILL.md +32 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@valentia-ai-skills/framework",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "AI development skills framework ÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂâÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂàcentralized coding standards, security patterns, and SOPs for AI-assisted development. Works with Claude Code, Cursor, Copilot, Windsurf, and any AI coding tool.",
|
|
3
|
+
"version": "1.0.14",
|
|
4
|
+
"description": "AI development skills framework ÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂâÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂàcentralized coding standards, security patterns, and SOPs for AI-assisted development. Works with Claude Code, Cursor, Copilot, Windsurf, and any AI coding tool.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-skills",
|
|
7
7
|
"claude-code",
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: aisupportapp/project-architecture
|
|
3
|
+
description: Auto-generated project-architecture for aisupportapp. Created by project-scanner.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
scope: project
|
|
6
|
+
last_reviewed: 2026-03-27
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
name: project-architecture
|
|
11
|
+
description: Architecture overview, data flow, layer diagram, and key abstractions for aiSupportApp — a single-page multi-step appointment booking wizard.
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Project Architecture — aiSupportApp
|
|
15
|
+
|
|
16
|
+
## Architecture Pattern
|
|
17
|
+
|
|
18
|
+
**Single-Page Application (SPA) with Wizard State Machine**
|
|
19
|
+
|
|
20
|
+
The app is a single-route React SPA orchestrated around a sequential, numbered step wizard. State is managed centrally in Redux (single slice). There is no server-side rendering, no API routes, and no backend in this repo. All data comes from an external REST API (`bookinggateway.vitonta.com`).
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Provider Hierarchy (Entry Point)
|
|
25
|
+
|
|
26
|
+
`src/main.tsx` establishes the provider stack from outermost to innermost:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
GoogleReCaptchaProvider ← Google reCAPTCHA v3 (bot protection)
|
|
30
|
+
└─ Provider (Redux) ← Global state store
|
|
31
|
+
└─ MantineProvider ← UI theme & component defaults
|
|
32
|
+
└─ ModalsProvider ← Mantine modal context
|
|
33
|
+
├─ Notifications (top-right)
|
|
34
|
+
└─ RouterProvider ← react-router-dom BrowserRouter
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Routing Layer
|
|
40
|
+
|
|
41
|
+
`src/router/index.tsx` — Two routes, both rendering `BookingPage`:
|
|
42
|
+
|
|
43
|
+
| Route | Component |
|
|
44
|
+
|---|---|
|
|
45
|
+
| `/` | `BookingPage` |
|
|
46
|
+
| `/booking` | `BookingPage` |
|
|
47
|
+
|
|
48
|
+
The `AppShell.tsx` layout component exists but is **not currently wired into the router** — it is a standalone Mantine shell with a header and footer, built as an optional wrapper. Step components each self-contain their own header/footer.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Layer Diagram
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
User Browser
|
|
56
|
+
│
|
|
57
|
+
├─ src/pages/BookingPage.tsx ← Wizard orchestrator (controls currentStep)
|
|
58
|
+
│ │
|
|
59
|
+
│ ├─ src/components/booking/
|
|
60
|
+
│ │ Step1Category.tsx ← Category selection
|
|
61
|
+
│ │ Step2Service.tsx ← Provider & service selection
|
|
62
|
+
│ │ Step3Location.tsx ← Location/clinic selection
|
|
63
|
+
│ │ Step4Clinician.tsx ← Clinician availability & date
|
|
64
|
+
│ │ Step5Schedule.tsx ← Time slot selection & reservation
|
|
65
|
+
│ │ Step6Patient.tsx ← Patient details form
|
|
66
|
+
│ │ Step7Payment.tsx ← Stripe payment
|
|
67
|
+
│ │ Step8Completion.tsx ← Confirmation screen
|
|
68
|
+
│ │
|
|
69
|
+
│ └─ src/hooks/ (useAppDispatch, useAppSelector)
|
|
70
|
+
│
|
|
71
|
+
├─ src/store/bookingSlice.ts ← Redux slice: state + reducers + async thunks
|
|
72
|
+
│ │
|
|
73
|
+
│ └─ src/api/bookingApi.ts ← Axios instance + typed API functions
|
|
74
|
+
│
|
|
75
|
+
└─ External REST API
|
|
76
|
+
https://bookinggateway.vitonta.com/{endpoint}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Key Abstractions
|
|
82
|
+
|
|
83
|
+
### BookingState (Single Source of Truth)
|
|
84
|
+
Defined in `src/store/bookingSlice.ts`. Divided into two top-level sections:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
interface BookingState {
|
|
88
|
+
status: 'idle' | 'loading' | 'succeeded' | 'failed';
|
|
89
|
+
error: string | null;
|
|
90
|
+
token: string | null;
|
|
91
|
+
setupData: {
|
|
92
|
+
categories: ServiceCategory[]; // from GetServiceCategory
|
|
93
|
+
providers: Provider[]; // from GetPracticeProvider
|
|
94
|
+
services: any[]; // from GetServiceMapping
|
|
95
|
+
locations: any[]; // from GetPracticeLocation
|
|
96
|
+
paymentConfig: any | null; // from GetPracticeforPaymentConfigration
|
|
97
|
+
dayRoster: any[]; // from GetDayRoaster
|
|
98
|
+
slots: any[]; // from SearchListOfSlot
|
|
99
|
+
isLoadingSlots: boolean;
|
|
100
|
+
};
|
|
101
|
+
selections: {
|
|
102
|
+
// All user selections accumulated as the wizard progresses
|
|
103
|
+
selectedCategoryID, selectedCategoryName,
|
|
104
|
+
selectedProviderID, selectedServiceID, selectedServiceName,
|
|
105
|
+
selectedServiceDuration, selectedServicePrice,
|
|
106
|
+
practiceLocationID, practiceLocationName,
|
|
107
|
+
selectedDate, selectedTime,
|
|
108
|
+
patientInfo, appointmentID, invoiceID,
|
|
109
|
+
appointmentCode, patientID, customerID, price
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Axios Instance (`bookingApi`)
|
|
115
|
+
`src/api/bookingApi.ts` — A pre-configured Axios instance:
|
|
116
|
+
- Base URL: `VITE_API_BASE_URL`
|
|
117
|
+
- Request interceptor: automatically attaches `Authorization: Bearer {token}` from `localStorage.getItem('bookingToken')`, skipped for `PublicAccessToken` endpoint.
|
|
118
|
+
|
|
119
|
+
### Typed Redux Hooks
|
|
120
|
+
`src/hooks/useAppDispatch.ts` exports both:
|
|
121
|
+
```ts
|
|
122
|
+
export const useAppDispatch: () => AppDispatch = useDispatch;
|
|
123
|
+
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
|
|
124
|
+
```
|
|
125
|
+
These are the **only approved way** to dispatch or select from the Redux store in components.
|
|
126
|
+
|
|
127
|
+
### Fetch-based `apiClient` Utility
|
|
128
|
+
`src/utils/apiClient.ts` — A generic typed fetch wrapper as an alternative to the Axios instance. Handles auth headers, 401 detection, and typed response parsing. Used optionally alongside `bookingApi.ts`.
|
|
129
|
+
|
|
130
|
+
### Mantine Theme
|
|
131
|
+
`src/theme/mantineTheme.ts` — Centralizes design tokens:
|
|
132
|
+
- Primary color: `brandBlue` (custom 10-shade palette, primary shade #5474b4)
|
|
133
|
+
- Font: `Inter` (body), `Outfit` (headings, bold)
|
|
134
|
+
- Default radius: `md`
|
|
135
|
+
- Button default: `xl` radius, `sm` size, 600 font-weight
|
|
136
|
+
- Card default: `lg` radius, `xl` padding, `sm` shadow, bordered
|
|
137
|
+
- Paper default: `lg` radius, `xl` padding, `sm` shadow
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Data Flow for a Typical Request
|
|
142
|
+
|
|
143
|
+
### Initialization (App Load → Step 1)
|
|
144
|
+
1. `BookingPage` mounts, `useEffect` triggers `dispatch(fetchInitialData(apiKey))`.
|
|
145
|
+
2. `fetchInitialData` thunk in `bookingSlice.ts`:
|
|
146
|
+
- Calls `getPublicAccessToken(apiKey)` → saves JWT to `localStorage('bookingToken')`.
|
|
147
|
+
- Calls `Promise.all([getPracticeProviders, getServiceCategory, getServiceMapping, getPaymentConfiguration])`.
|
|
148
|
+
3. `extraReducers` handles `pending` → sets `status: 'loading'`, `fulfilled` → sets `status: 'succeeded'` and populates `setupData`.
|
|
149
|
+
4. `BookingPage` re-renders, shows `Step1Category`.
|
|
150
|
+
5. `Step1Category` reads `categories` and `services` from `useAppSelector((s) => s.booking.setupData)`.
|
|
151
|
+
|
|
152
|
+
### User Selection (Step 1 → Step 2)
|
|
153
|
+
1. User clicks a category card → `dispatch(setCategory({ id, name }))`.
|
|
154
|
+
2. Reducer updates `state.selections.selectedCategoryID/Name`.
|
|
155
|
+
3. User clicks "Next Step" → `onNext()` prop callback is called.
|
|
156
|
+
4. `BookingPage` increments `currentStep` → renders `Step2Service`.
|
|
157
|
+
|
|
158
|
+
### Booking Submission (Step 7)
|
|
159
|
+
1. `submitBooking` thunk reads all selections from `getState()`.
|
|
160
|
+
2. Orchestrates 5 sequential API calls: search patient → add patient (if new) → add appointment → create payment intent → finalize appointment.
|
|
161
|
+
3. Each failure calls `rejectWithValue(error.response?.data || error.message)`.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Authentication & Authorization Flow
|
|
166
|
+
|
|
167
|
+
1. **Public token**: `POST /PublicAccessToken` with raw JSON string payload `"practiceApiKey"`.
|
|
168
|
+
2. Token stored in `localStorage('bookingToken')`.
|
|
169
|
+
3. All subsequent Axios requests automatically receive `Authorization: Bearer {token}` via request interceptor in `bookingApi.ts`.
|
|
170
|
+
4. Google reCAPTCHA v3 (`react-google-recaptcha-v3`) wraps the entire app for bot protection.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## External Service Integrations
|
|
175
|
+
|
|
176
|
+
| Service | Purpose | Integration Point |
|
|
177
|
+
|---|---|---|
|
|
178
|
+
| `bookinggateway.vitonta.com` | Core booking REST API | `src/api/bookingApi.ts` |
|
|
179
|
+
| Stripe | Payment processing | `src/utils/StripeConfig.ts`, `@stripe/react-stripe-js` (Step7Payment) |
|
|
180
|
+
| Google reCAPTCHA v3 | Bot protection | `main.tsx` + `src/hooks/useRecaptcha.ts` |
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Reference Implementations
|
|
185
|
+
|
|
186
|
+
| Pattern | Best Example |
|
|
187
|
+
|---|---|
|
|
188
|
+
| Redux async thunk | `fetchInitialData` in `src/store/bookingSlice.ts` (L107-133) |
|
|
189
|
+
| Orchestrated multi-step thunk | `submitBooking` in `src/store/bookingSlice.ts` (L201-270) |
|
|
190
|
+
| Step component (simple) | `src/components/booking/Step1Category.tsx` |
|
|
191
|
+
| Step component (complex, with roster/calendar) | `src/components/booking/Step5Schedule.tsx` |
|
|
192
|
+
| API layer | `src/api/bookingApi.ts` |
|
|
193
|
+
| Redux state shape | `BookingState` interface in `src/store/bookingSlice.ts` (L35-69) |
|
|
194
|
+
| Typed hooks | `src/hooks/useAppDispatch.ts` |
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: aisupportapp/project-conventions
|
|
3
|
+
description: Auto-generated project-conventions for aisupportapp. Created by project-scanner.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
scope: project
|
|
6
|
+
last_reviewed: 2026-03-27
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
name: project-conventions
|
|
11
|
+
description: Naming conventions, code patterns, file structure, and project-specific idioms for aiSupportApp — a multi-step appointment booking wizard for Axis Sport & Medicine / HealthSync Portal.
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Project Conventions — aiSupportApp
|
|
15
|
+
|
|
16
|
+
## Project Overview
|
|
17
|
+
|
|
18
|
+
**aiSupportApp** is a React-based, multi-step appointment booking wizard for a healthcare/sports medicine practice (branded as "Axis Sport & Medicine" / "HealthSync Portal"). It guides patients through 8 sequential steps: category selection → service & provider → location → clinician availability → time scheduling → patient details → payment → confirmation.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Tech Stack (Exact Versions)
|
|
23
|
+
|
|
24
|
+
| Technology | Version |
|
|
25
|
+
|---|---|
|
|
26
|
+
| React | ^19.2.0 |
|
|
27
|
+
| TypeScript | ~5.9.3 |
|
|
28
|
+
| Vite | ^8.0.0-beta.13 |
|
|
29
|
+
| Redux Toolkit | ^2.11.2 |
|
|
30
|
+
| react-redux | ^9.2.0 |
|
|
31
|
+
| react-router-dom | ^7.13.1 |
|
|
32
|
+
| @mantine/core | ^8.3.15 |
|
|
33
|
+
| @mantine/dates | ^8.3.15 |
|
|
34
|
+
| @mantine/form | ^8.3.15 |
|
|
35
|
+
| @mantine/notifications | ^8.3.15 |
|
|
36
|
+
| @mantine/modals | ^8.3.15 |
|
|
37
|
+
| @tabler/icons-react | ^3.38.0 |
|
|
38
|
+
| axios | ^1.13.6 |
|
|
39
|
+
| @stripe/react-stripe-js | ^5.6.1 |
|
|
40
|
+
| date-fns | ^4.1.0 |
|
|
41
|
+
| dayjs | ^1.11.19 |
|
|
42
|
+
| tailwindcss | ^4.2.1 |
|
|
43
|
+
| postcss-preset-mantine | ^1.18.0 |
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Naming Conventions
|
|
48
|
+
|
|
49
|
+
### Variables & Functions
|
|
50
|
+
- **camelCase** for all variables and functions.
|
|
51
|
+
- Examples: `handleSelectCategory`, `getServiceCount`, `fetchInitialData`, `selectedCategoryID`.
|
|
52
|
+
- Selector callbacks use arrow functions: `(state) => state.booking.selections.selectedCategoryID`.
|
|
53
|
+
|
|
54
|
+
### Components & Files
|
|
55
|
+
- **PascalCase** for React component filenames and their default export function names.
|
|
56
|
+
- Examples: `Step1Category.tsx`, `BookingPage.tsx`, `AppShell.tsx`, `Step5Schedule.tsx`.
|
|
57
|
+
- One component per file. File name matches the exported component name exactly.
|
|
58
|
+
|
|
59
|
+
### Folders
|
|
60
|
+
- **camelCase** for non-component folders: `api/`, `store/`, `hooks/`, `utils/`, `config/`, `router/`, `theme/`.
|
|
61
|
+
- **PascalCase-like** folders for feature groupings under `components/`: `booking/`, `layout/`.
|
|
62
|
+
|
|
63
|
+
### Redux Actions (Slice Reducers)
|
|
64
|
+
- **camelCase** prefixed with the operation verb: `setCategory`, `setLocation`, `setSchedule`, `setPatientInfo`, `resetBooking`.
|
|
65
|
+
- Async thunks use descriptive names: `fetchInitialData`, `fetchLocations`, `fetchDayRoster`, `fetchSlots`, `submitBooking`.
|
|
66
|
+
- Async thunk IDs follow `sliceName/actionName`: `'booking/fetchInitialData'`.
|
|
67
|
+
|
|
68
|
+
### API Endpoint Variables
|
|
69
|
+
- API functions use **camelCase** prefixed with `get`, `add`, `create`, `search`, `finalize`: `getPublicAccessToken`, `addAppointment`, `createPayment`, `searchExistingPatient`.
|
|
70
|
+
- See `src/api/bookingApi.ts` for the complete list.
|
|
71
|
+
|
|
72
|
+
### TypeScript Interfaces
|
|
73
|
+
- **PascalCase** for all interfaces: `BookingState`, `Provider`, `ServiceCategory`, `ApiClientOptions`.
|
|
74
|
+
- Interfaces are defined inline in the same file where they are consumed — no separate `types/` folder.
|
|
75
|
+
|
|
76
|
+
### Environment Variables
|
|
77
|
+
- Prefix: `VITE_` (required for Vite to expose them to the browser).
|
|
78
|
+
- Named with SCREAMING_SNAKE_CASE: `VITE_API_BASE_URL`, `VITE_PRACTICE_API_KEY`, `VITE_RECAPTCHA_SITE_KEY`.
|
|
79
|
+
- Accessed through `src/config/constants.ts` via `import.meta.env.VITE_*`.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## File Structure Rules
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
src/
|
|
87
|
+
api/ ← Axios-based API functions (one file: bookingApi.ts)
|
|
88
|
+
components/
|
|
89
|
+
booking/ ← Step wizard components (Step1Category.tsx … Step8Completion.tsx)
|
|
90
|
+
layout/ ← AppShell layout wrapper (AppShell.tsx)
|
|
91
|
+
config/ ← constants.ts (env vars re-exported as named constants)
|
|
92
|
+
hooks/ ← Typed Redux hooks (useAppDispatch.ts, useAppSelector.ts, useRecaptcha.ts)
|
|
93
|
+
pages/ ← Top-level route components (BookingPage.tsx)
|
|
94
|
+
router/ ← react-router-dom config (index.tsx)
|
|
95
|
+
store/ ← Redux store (index.ts, bookingSlice.ts)
|
|
96
|
+
theme/ ← Mantine theme config (mantineTheme.ts)
|
|
97
|
+
utils/ ← Shared utilities (apiClient.ts, dateUtils.ts, StripeConfig.ts)
|
|
98
|
+
main.tsx ← App entry point & provider hierarchy
|
|
99
|
+
App.tsx ← Legacy Vite placeholder (not used in routing)
|
|
100
|
+
index.css ← Global CSS & Tailwind custom properties
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Where to create new files:**
|
|
104
|
+
- New booking step components → `src/components/booking/StepNName.tsx`
|
|
105
|
+
- New API functions → add to `src/api/bookingApi.ts`
|
|
106
|
+
- New Redux slices → `src/store/sliceName.ts`, then register in `src/store/index.ts`
|
|
107
|
+
- New pages → `src/pages/PageName.tsx`, then define route in `src/router/index.tsx`
|
|
108
|
+
- New utilities → `src/utils/utilName.ts`
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Import & Export Patterns
|
|
113
|
+
|
|
114
|
+
### Absolute Path Alias
|
|
115
|
+
- The `@/` alias resolves to `src/`. Use it for all cross-directory imports.
|
|
116
|
+
- Examples from `src/main.tsx`:
|
|
117
|
+
```ts
|
|
118
|
+
import { router } from '@/router';
|
|
119
|
+
import { theme } from '@/theme/mantineTheme';
|
|
120
|
+
import { RECAPTCHA_SITE_KEY } from '@/config/constants';
|
|
121
|
+
import { store } from '@/store';
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Component Imports (from siblings)
|
|
125
|
+
- Step components use **relative paths** when importing within the same directory:
|
|
126
|
+
```ts
|
|
127
|
+
import { useAppSelector } from '../../hooks/useAppSelector';
|
|
128
|
+
import { useAppDispatch } from '../../hooks/useAppDispatch';
|
|
129
|
+
import { setCategory } from '../../store/bookingSlice';
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Export Style
|
|
133
|
+
- **Named exports** for actions, thunks, types, hooks, utilities:
|
|
134
|
+
```ts
|
|
135
|
+
export const { setCategory, resetBooking } = bookingSlice.actions;
|
|
136
|
+
export type RootState = ReturnType<typeof store.getState>;
|
|
137
|
+
export type AppDispatch = typeof store.dispatch;
|
|
138
|
+
```
|
|
139
|
+
- **Default exports** for React components and Redux reducers:
|
|
140
|
+
```ts
|
|
141
|
+
export default bookingSlice.reducer;
|
|
142
|
+
export default function Step1Category({ onNext, onClose }: Step1Props) { ... }
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### CSS/Style Imports in `main.tsx`
|
|
146
|
+
Order matters — always import Mantine styles before app CSS:
|
|
147
|
+
```ts
|
|
148
|
+
import '@mantine/core/styles.css';
|
|
149
|
+
import '@mantine/dates/styles.css';
|
|
150
|
+
import '@mantine/notifications/styles.css';
|
|
151
|
+
import '@/index.css';
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Error Handling Pattern
|
|
157
|
+
|
|
158
|
+
### Async Thunks
|
|
159
|
+
All async thunks use a consistent try/catch with `rejectWithValue`:
|
|
160
|
+
```ts
|
|
161
|
+
// See src/store/bookingSlice.ts
|
|
162
|
+
export const fetchInitialData = createAsyncThunk(
|
|
163
|
+
'booking/fetchInitialData',
|
|
164
|
+
async (practiceApiKey: string, { rejectWithValue }) => {
|
|
165
|
+
try {
|
|
166
|
+
// ... async work
|
|
167
|
+
} catch (error: any) {
|
|
168
|
+
return rejectWithValue(error.response?.data || error.message);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### apiClient.ts (fetch-based utility)
|
|
175
|
+
- Throws `'UNAUTHORIZED'` error string on 401.
|
|
176
|
+
- Throws `API error {status} on {endpoint}` for other non-OK responses.
|
|
177
|
+
- See `src/utils/apiClient.ts`.
|
|
178
|
+
|
|
179
|
+
### UI Error States
|
|
180
|
+
- Components check `status === 'failed'` from Redux state and display an error div:
|
|
181
|
+
```tsx
|
|
182
|
+
// See src/pages/BookingPage.tsx
|
|
183
|
+
if (status === 'failed') {
|
|
184
|
+
return <div className="p-4 bg-red-50 text-red-600 rounded-lg">{error}</div>;
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Coding Patterns Checklist
|
|
191
|
+
|
|
192
|
+
- ✅ **Always use typed Redux hooks** — `useAppDispatch()` and `useAppSelector()` from `src/hooks/`. Never use raw `useDispatch`/`useSelector`.
|
|
193
|
+
- ✅ **Step components receive callback props** — `onNext`, `onBack`, `onClose` — passed down from `BookingPage.tsx`.
|
|
194
|
+
- ✅ **Store state is read via `useAppSelector`**, never via local state cache.
|
|
195
|
+
- ✅ **Mixed styling**: Mantine components for UI controls (modals, notifications, forms), TailwindCSS utility classes for layout and step page shells.
|
|
196
|
+
- ✅ **Custom CSS variables** are used for brand colors in Tailwind classes: `bg-primary`, `text-primary`, `bg-background-light`, `bg-background-dark`. These are defined in `src/index.css`.
|
|
197
|
+
- ✅ **Material Symbols Outlined** icon font is used in step components (loaded via `index.html`).
|
|
198
|
+
- ✅ **Tabler Icons** from `@tabler/icons-react` used in Mantine layout components.
|
|
199
|
+
- ✅ **`date-fns/format`** is used for date formatting in thunks (dates as `MM/dd/yyyy` for API requests).
|
|
200
|
+
- ✅ **`localStorage`** is used to persist the Bearer token between page refreshes: key `'bookingToken'`.
|
|
201
|
+
- ✅ **`import.meta.env.VITE_PRACTICE_ID`** is accessed directly in thunks with a zero-UUID fallback.
|
|
202
|
+
- ❌ **No test files exist** — do not assume a testing framework is in use.
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: aisupportapp/project-workflows
|
|
3
|
+
description: Auto-generated project-workflows for aisupportapp. Created by project-scanner.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
scope: project
|
|
6
|
+
last_reviewed: 2026-03-27
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
name: project-workflows
|
|
11
|
+
description: How to run, build, deploy, add features, and extend the aiSupportApp appointment booking wizard.
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Project Workflows — aiSupportApp
|
|
15
|
+
|
|
16
|
+
## Running Locally
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Install dependencies
|
|
20
|
+
npm install
|
|
21
|
+
|
|
22
|
+
# Start development server (Vite HMR)
|
|
23
|
+
npm run dev
|
|
24
|
+
# → Runs at http://localhost:5173 (default Vite port)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Before running, ensure `.env` is configured:**
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# .env (copy from .env.example)
|
|
31
|
+
VITE_API_BASE_URL=https://bookinggateway.vitonta.com
|
|
32
|
+
VITE_PRACTICE_API_KEY=your_practice_api_key_here
|
|
33
|
+
VITE_RECAPTCHA_SITE_KEY=your_google_recaptcha_v3_site_key
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
> ⚠️ The app will display "Initialization Failed" on load if `VITE_PRACTICE_API_KEY` is missing or incorrect. The `PublicAccessToken` API call will fail.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Build for Production
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm run build
|
|
44
|
+
# Outputs to dist/
|
|
45
|
+
|
|
46
|
+
npm run preview
|
|
47
|
+
# Preview the production build locally
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Linting
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npm run lint
|
|
56
|
+
# Runs ESLint across all .ts and .tsx files
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Testing
|
|
62
|
+
|
|
63
|
+
**No test suite currently exists.** There are no `.test.ts`, `.spec.ts`, or test runner configurations (Jest, Vitest, Playwright) in this project. Manual browser testing is the current approach.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Adding a New Booking Step
|
|
68
|
+
|
|
69
|
+
Follow the established 8-step pattern:
|
|
70
|
+
|
|
71
|
+
1. **Create the component** → `src/components/booking/StepNName.tsx`
|
|
72
|
+
- Accept `onNext`, `onBack`, `onClose` as props (typed inline interface).
|
|
73
|
+
- Use `useAppDispatch()` and `useAppSelector()` (from `src/hooks/`) for Redux I/O.
|
|
74
|
+
- Style with TailwindCSS utility classes. Use `bg-primary`, `text-primary`, `bg-background-light` CSS custom properties.
|
|
75
|
+
- Add a progress bar showing `{N/8 * 100}% Complete`.
|
|
76
|
+
|
|
77
|
+
2. **Add Redux action** → `src/store/bookingSlice.ts`
|
|
78
|
+
- For synchronous selections, add to the `reducers` object:
|
|
79
|
+
```ts
|
|
80
|
+
setMySelection: (state, action: PayloadAction<{ id: string }>) => {
|
|
81
|
+
state.selections.mySelectionID = action.payload.id;
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
- For async data fetching, add a new `createAsyncThunk`:
|
|
85
|
+
```ts
|
|
86
|
+
export const fetchMyData = createAsyncThunk(
|
|
87
|
+
'booking/fetchMyData',
|
|
88
|
+
async (params, { rejectWithValue }) => {
|
|
89
|
+
try {
|
|
90
|
+
return await myApiFunction(params);
|
|
91
|
+
} catch (error: any) {
|
|
92
|
+
return rejectWithValue(error.response?.data || error.message);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
```
|
|
97
|
+
- Handle it in `extraReducers`.
|
|
98
|
+
|
|
99
|
+
3. **Add API function** → `src/api/bookingApi.ts`
|
|
100
|
+
- Add a typed async function using the pre-configured `bookingApi` Axios instance:
|
|
101
|
+
```ts
|
|
102
|
+
export const myNewApiCall = async (payload: MyPayloadType) => {
|
|
103
|
+
const response = await bookingApi.post('/MyEndpoint', payload);
|
|
104
|
+
return response.data;
|
|
105
|
+
};
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
4. **Register in BookingPage** → `src/pages/BookingPage.tsx`
|
|
109
|
+
- Import the new step component.
|
|
110
|
+
- Add conditional render: `{currentStep === N && <StepNName onNext={handleNext} onBack={handleBack} onClose={handleClose} />}`
|
|
111
|
+
- Update `Math.min(prev + 1, N_MAX)` in `handleNext`.
|
|
112
|
+
|
|
113
|
+
5. **No router changes needed** — all steps render under the same `/` or `/booking` route.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Adding a New API Endpoint
|
|
118
|
+
|
|
119
|
+
1. Add a typed function in `src/api/bookingApi.ts`:
|
|
120
|
+
```ts
|
|
121
|
+
export const getMyResource = async (id: string) => {
|
|
122
|
+
const response = await bookingApi.get(`/GetMyResource?id=${id}`);
|
|
123
|
+
return response.data;
|
|
124
|
+
};
|
|
125
|
+
```
|
|
126
|
+
2. Import and call from an async thunk in `src/store/bookingSlice.ts`.
|
|
127
|
+
3. The Axios instance handles token injection automatically — do not manually set `Authorization` headers unless overriding.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Adding a New Redux Slice
|
|
132
|
+
|
|
133
|
+
1. Create `src/store/myFeatureSlice.ts` following the `bookingSlice.ts` pattern.
|
|
134
|
+
2. Register it in `src/store/index.ts`:
|
|
135
|
+
```ts
|
|
136
|
+
import myFeatureReducer from './myFeatureSlice';
|
|
137
|
+
|
|
138
|
+
export const store = configureStore({
|
|
139
|
+
reducer: {
|
|
140
|
+
booking: bookingReducer,
|
|
141
|
+
myFeature: myFeatureReducer, // ← add here
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
3. Update `RootState` type automatically (it uses `ReturnType<typeof store.getState>`).
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Adding a New Route / Page
|
|
150
|
+
|
|
151
|
+
1. Create `src/pages/NewPage.tsx`.
|
|
152
|
+
2. Add the route in `src/router/index.tsx`:
|
|
153
|
+
```tsx
|
|
154
|
+
import NewPage from '@/pages/NewPage';
|
|
155
|
+
|
|
156
|
+
export const router = createBrowserRouter([
|
|
157
|
+
{ path: '/', element: <BookingPage /> },
|
|
158
|
+
{ path: '/booking', element: <BookingPage /> },
|
|
159
|
+
{ path: '/new-path', element: <NewPage /> }, // ← add here
|
|
160
|
+
]);
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Updating the Mantine Theme
|
|
166
|
+
|
|
167
|
+
Edit `src/theme/mantineTheme.ts`. The `theme` object is passed to `<MantineProvider>` in `main.tsx`. Component overrides use `ComponentName.extend({ defaultProps, styles })` pattern:
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
// Example: customize TextInput globally
|
|
171
|
+
TextInput: TextInput.extend({
|
|
172
|
+
defaultProps: { radius: 'md', size: 'sm' },
|
|
173
|
+
styles: { input: { borderColor: 'var(--mantine-color-brandBlue-4)' } }
|
|
174
|
+
})
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Environment Variables Reference
|
|
180
|
+
|
|
181
|
+
| Variable | Required | Description |
|
|
182
|
+
|---|---|---|
|
|
183
|
+
| `VITE_API_BASE_URL` | ✅ Yes | Base URL for the booking REST API (e.g. `https://bookinggateway.vitonta.com`) |
|
|
184
|
+
| `VITE_PRACTICE_API_KEY` | ✅ Yes | Practice API key used for `PublicAccessToken` auth and as `PracticeID` in API calls |
|
|
185
|
+
| `VITE_RECAPTCHA_SITE_KEY` | ✅ Yes | Google reCAPTCHA v3 site key |
|
|
186
|
+
| `VITE_PRACTICE_ID` | ⚠️ Optional | UUID for the practice; thunks fall back to `'00000000-0000-0000-0000-000000000000'` if absent |
|
|
187
|
+
|
|
188
|
+
> Always access via `src/config/constants.ts` exports, not `import.meta.env.*` directly in components.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## API Integration Reference
|
|
193
|
+
|
|
194
|
+
The canonical reference for all API calls, payloads, and UI data mappings is `appliworkflowfile.md` at the project root. Always consult it before implementing or modifying any API integration.
|
|
195
|
+
|
|
196
|
+
### API Call Sequence (Booking Flow)
|
|
197
|
+
|
|
198
|
+
| Step | API Call | Type |
|
|
199
|
+
|---|---|---|
|
|
200
|
+
| Init | `POST /PublicAccessToken` | Auth |
|
|
201
|
+
| Init | `GET /GetPracticeProvider` | Parallel |
|
|
202
|
+
| Init | `GET /GetServiceCategory` | Parallel |
|
|
203
|
+
| Init | `GET /GetServiceMapping` | Parallel |
|
|
204
|
+
| Init | `GET /GetPracticeforPaymentConfigration` | Parallel |
|
|
205
|
+
| Step 3 | `GET /GetPracticeLocation` | On demand |
|
|
206
|
+
| Step 4 | `POST /GetFirstAvailableSlotforMultiProvider` | On load |
|
|
207
|
+
| Step 4 | `POST /GetDayRoaster` | On clinician select |
|
|
208
|
+
| Step 5 | `POST /SearchListOfSlot` | On date select |
|
|
209
|
+
| Step 5 | `POST /AddAppointment` (draft) | On "Continue" |
|
|
210
|
+
| Step 6 | `POST /SearchExistingAutoMapPatient` | On "Continue" |
|
|
211
|
+
| Step 6 | `POST /AddePatient` (if new) | Conditional |
|
|
212
|
+
| Step 7 | `POST /CreatePayment` | On load |
|
|
213
|
+
| Step 8 | `POST /FinalizeAppointment` | On load |
|
|
214
|
+
|
|
215
|
+
> ⚠️ Note the intentional typo in the API: `AddePatient` (not `AddPatient`). This is the live endpoint name and must be preserved.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Supabase Skill Sync (`.ai-skills.json`)
|
|
220
|
+
|
|
221
|
+
The project is configured to push scan results to Supabase:
|
|
222
|
+
|
|
223
|
+
```json
|
|
224
|
+
{
|
|
225
|
+
"email": "haseeb.ahmed@valentiatech.com",
|
|
226
|
+
"scanUrl": "https://znshdhjquohrzvbnloki.supabase.co/functions/v1/scan-results"
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
After running a project scan, a `POST` to `scanUrl` delivers updated skill content for storage.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: aisupportapp/test-installation
|
|
3
|
+
description: No description
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
scope: project
|
|
6
|
+
last_reviewed: 2026-03-27
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Skill Name
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
Describe what this skill covers and when it should be applied.
|
|
14
|
+
|
|
15
|
+
## 1. First Rule
|
|
16
|
+
|
|
17
|
+
- Rule details here
|
|
18
|
+
- Use clear, actionable language
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
// ✅ Good
|
|
22
|
+
const example = 'good pattern'
|
|
23
|
+
|
|
24
|
+
// ❌ Bad
|
|
25
|
+
const example = 'bad pattern'
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Checklist
|
|
29
|
+
|
|
30
|
+
- [ ] First check
|
|
31
|
+
- [ ] Second check
|
|
32
|
+
- [ ] Third check
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: appointment-oas-app
|
|
3
|
+
description: No description
|
|
4
|
+
version: 1.0.1
|
|
5
|
+
scope: global
|
|
6
|
+
last_reviewed: 2026-03-27
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
name: appointment-booking-app
|
|
11
|
+
description: >
|
|
12
|
+
Build a complete appointment booking web application in React JS (Vite + Tailwind + Redux Toolkit + React Query).
|
|
13
|
+
This skill handles TWO phases: (1) pixel-perfect UI replication from any design input — Figma exports, HTML/CSS mockups,
|
|
14
|
+
or screenshot images — auto-detecting whether the UI is a wizard/stepper, single-page form, tabbed layout, or other pattern;
|
|
15
|
+
and (2) full API integration with business rules across a 6-step booking flow including authentication, service/category
|
|
16
|
+
selection, clinic/location filtering, provider selection with first-available slots, calendar/slot picker, patient
|
|
17
|
+
registration with NZ address lookup (eSAM), and Stripe payment.
|
|
18
|
+
|
|
19
|
+
USE THIS SKILL whenever the user asks to: build an appointment booking app or flow, replicate a booking UI from a design,
|
|
20
|
+
wire up booking APIs, implement a multi-step scheduling wizard, create a date/time picker booking interface, or anything
|
|
21
|
+
involving appointment scheduling with API integration. Also trigger when the user shares a Figma link, HTML mockup,
|
|
22
|
+
or screenshot and says "build this" or "replicate this" and the context is a booking or scheduling flow.
|
|
23
|
+
Trigger even if they just say "booking app", "appointment page", "scheduling UI", or share a design with calendar/time elements.
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# Appointment Booking App Skill
|
|
27
|
+
|
|
28
|
+
This skill builds a production-grade appointment booking web application in two phases:
|
|
29
|
+
- **Phase 1 — UI Replication**: Pixel-perfect reproduction of a provided design
|
|
30
|
+
- **Phase 2 — API Integration**: 6-step API wiring with business rules
|
|
31
|
+
|
|
32
|
+
## Tech Stack (Non-negotiable)
|
|
33
|
+
|
|
34
|
+
| Layer | Choice |
|
|
35
|
+
|-------------------|-------------------------------|
|
|
36
|
+
| Build tool | Vite + React |
|
|
37
|
+
| Styling | Tailwind CSS |
|
|
38
|
+
| State management | Redux Toolkit (global state) |
|
|
39
|
+
| Server state | React Query / TanStack Query |
|
|
40
|
+
| Routing | React Router v6 |
|
|
41
|
+
| HTTP client | Axios (with interceptors) |
|
|
42
|
+
| Payment | Stripe.js + @stripe/react-stripe-js |
|
|
43
|
+
|
|
44
|
+
## Environment Variables (Vite standard)
|
|
45
|
+
|
|
46
|
+
```env
|
|
47
|
+
VITE_S_PRACTICE_ID=<encrypted practice ID>
|
|
48
|
+
VITE_API_BASE_URL=https://bookinggateway.vitonta.com
|
|
49
|
+
VITE_STRIPE_PUBLISHABLE_KEY=<stripe publishable key>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Phase 1 — UI Replication
|
|
55
|
+
|
|
56
|
+
Read `references/ui-replication.md` for the full design-to-code workflow including:
|
|
57
|
+
- Design input detection (Figma/HTML/screenshot)
|
|
58
|
+
- UI pattern auto-detection (wizard, split-panel, calendar-first, etc.)
|
|
59
|
+
- Design token extraction and Tailwind config mapping
|
|
60
|
+
- Component patterns (stepper, calendar grid, provider cards, booking summary)
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Phase 2 — API Integration (6-Step Booking Flow)
|
|
65
|
+
|
|
66
|
+
Read `references/api-contracts.md` for complete endpoint specs, payloads, and response shapes.
|
|
67
|
+
Read `references/business-rules.md` for filtering logic, validation rules, and state transitions.
|
|
68
|
+
|
|
69
|
+
### Flow Overview
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
Step 0: POST /PublicAccessToken → JWT token (Bearer auth for all calls)
|
|
73
|
+
↓
|
|
74
|
+
Step 1: GET /GetServiceCategory?practiceID={id} → User picks a category
|
|
75
|
+
↓
|
|
76
|
+
Step 2: GET /GetServiceMapping → Filter services by category keywords across `serviceName` and `indiciReasonForContactTitle`
|
|
77
|
+
↓
|
|
78
|
+
Step 3: GET /GetPracticeLocation → Filter locations by serviceID
|
|
79
|
+
↓
|
|
80
|
+
Step 4: GET /GetPracticeProvider + POST /GetFirstAvailableSlotforMultiProvider
|
|
81
|
+
→ Filter providers by serviceID + locationID, show first available slots
|
|
82
|
+
↓
|
|
83
|
+
Step 5: POST /GetDayRoaster + POST /SearchListOfSlot
|
|
84
|
+
→ Calendar on left, time slots on right
|
|
85
|
+
↓
|
|
86
|
+
Step 6: Patient Registration + Address Lookup + Booking + Payment
|
|
87
|
+
→ Multiple sub-APIs (see api-contracts.md Step 6)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Redux Slice Structure
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
// store/bookingSlice.js
|
|
94
|
+
const bookingSlice = createSlice({
|
|
95
|
+
name: 'booking',
|
|
96
|
+
initialState: {
|
|
97
|
+
currentStep: 0,
|
|
98
|
+
token: null,
|
|
99
|
+
selectedCategory: null, // Step 1
|
|
100
|
+
selectedService: null, // Step 2
|
|
101
|
+
selectedLocation: null, // Step 3
|
|
102
|
+
selectedProvider: null, // Step 4
|
|
103
|
+
firstAvailableSlots: [], // Step 4
|
|
104
|
+
dayRoster: [], // Step 5
|
|
105
|
+
selectedDate: null, // Step 5
|
|
106
|
+
selectedSlots: [], // Step 5 (array — may need 2+ for longer durations)
|
|
107
|
+
appointmentID: null, // Step 6 (from AddAppointment)
|
|
108
|
+
invoiceID: null, // Step 6
|
|
109
|
+
patient: null, // Step 6
|
|
110
|
+
paymentIntent: null, // Step 6
|
|
111
|
+
},
|
|
112
|
+
reducers: { /* one setter per field + resetBooking */ },
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### React Query Hook Pattern
|
|
117
|
+
|
|
118
|
+
```javascript
|
|
119
|
+
// Every API step gets a dedicated hook
|
|
120
|
+
export const useServiceCategories = (practiceID) => useQuery({
|
|
121
|
+
queryKey: ['serviceCategories', practiceID],
|
|
122
|
+
queryFn: () => api.getServiceCategories(practiceID),
|
|
123
|
+
enabled: !!practiceID,
|
|
124
|
+
staleTime: 10 * 60 * 1000,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Mutations for POST endpoints
|
|
128
|
+
export const useAddAppointment = () => useMutation({
|
|
129
|
+
mutationFn: (payload) => api.addAppointment(payload),
|
|
130
|
+
onSuccess: (data) => { dispatch(setAppointmentID(data.appointmentID)); },
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Slot Booking Duration Logic (CRITICAL)
|
|
135
|
+
|
|
136
|
+
When booking, the number of slots to reserve depends on the service's `timeDuration` vs the slot `interval`:
|
|
137
|
+
```
|
|
138
|
+
slotsNeeded = Math.ceil(service.timeDuration / slot.interval)
|
|
139
|
+
```
|
|
140
|
+
Example: If `timeDuration` is 40 mins and slots are 20 min intervals → book 2 consecutive slots.
|
|
141
|
+
The `SlotID` array in `AddAppointment` must contain that many consecutive slot IDs.
|
|
142
|
+
|
|
143
|
+
### Error Handling
|
|
144
|
+
|
|
145
|
+
- Every API call must have loading, success, and error states in UI.
|
|
146
|
+
- Network failures → "Connection issue. Please try again."
|
|
147
|
+
- 4xx → map to business rule messages per step.
|
|
148
|
+
- 5xx → "Something went wrong on our end. Please try again later."
|
|
149
|
+
- Slot conflict (409) → refresh available slots and notify user.
|
|
150
|
+
|
|
151
|
+
### Checklist Before Delivering
|
|
152
|
+
|
|
153
|
+
- [ ] All design tokens in `tailwind.config.js`
|
|
154
|
+
- [ ] UI pattern correctly identified and implemented
|
|
155
|
+
- [ ] All API steps wired with React Query hooks
|
|
156
|
+
- [ ] Redux slice holds cross-step booking state
|
|
157
|
+
- [ ] Service filtering uses meaningful category keywords against `serviceName` and `indiciReasonForContactTitle`
|
|
158
|
+
- [ ] Location filtering by serviceID
|
|
159
|
+
- [ ] Provider dual-filter: serviceID + locationID
|
|
160
|
+
- [ ] Slot duration logic: consecutive slot booking
|
|
161
|
+
- [ ] eSAM address autocomplete + detail fetch
|
|
162
|
+
- [ ] Stripe payment integration with clientSecret
|
|
163
|
+
- [ ] Loading spinners on every async operation
|
|
164
|
+
- [ ] Error states handled for every API call
|
|
165
|
+
- [ ] Client-side validation before each API call
|
|
166
|
+
- [ ] Step 6 Mantine form initializes from a cloned draft object, not frozen Redux state
|
|
167
|
+
- [ ] Step 6 does not use unconditional `form.setValues(...)` sync effects that can cause update-depth loops
|
|
168
|
+
- [ ] Back navigation preserves state (React Query cache)
|
|
169
|
+
- [ ] AddAppointment fires on Step 6 page mount (before patient registration)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: viteapp/core-workflows
|
|
3
|
+
description: No description
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
scope: project
|
|
6
|
+
last_reviewed: 2026-03-27
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Skill Name
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
Describe what this skill covers and when it should be applied.
|
|
14
|
+
|
|
15
|
+
## 1. First Rule
|
|
16
|
+
|
|
17
|
+
- Rule details here
|
|
18
|
+
- Use clear, actionable language
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
// ✅ Good
|
|
22
|
+
const example = 'good pattern'
|
|
23
|
+
|
|
24
|
+
// ❌ Bad
|
|
25
|
+
const example = 'bad pattern'
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Checklist
|
|
29
|
+
|
|
30
|
+
- [ ] First check
|
|
31
|
+
- [ ] Second check
|
|
32
|
+
- [ ] Third check
|