mirror of
https://github.com/lucasrcsantana/story-generator.git
synced 2025-12-16 21:37:51 +00:00
refactor: atualiza dialog de confirmação para AlertDialog no EssayPage
- Substitui Dialog básico pelo AlertDialog especializado - Melhora feedback visual na confirmação de deleção - Mantém consistência com o design system - Implementa padrões de acessibilidade do Radix UI
This commit is contained in:
parent
d1e44f84b7
commit
da62f5e722
274
package-lock.json
generated
274
package-lock.json
generated
@ -16,8 +16,10 @@
|
||||
"@opentelemetry/sdk-metrics": "^1.30.1",
|
||||
"@opentelemetry/sdk-trace-web": "^1.30.1",
|
||||
"@radix-ui/react-accordion": "^1.2.2",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.6",
|
||||
"@radix-ui/react-dialog": "^1.1.4",
|
||||
"@radix-ui/react-progress": "^1.1.1",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-tabs": "^1.1.2",
|
||||
"@radix-ui/react-toast": "^1.2.4",
|
||||
"@sentry/react": "^8.48.0",
|
||||
@ -46,6 +48,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.9.1",
|
||||
"@shadcn/ui": "^0.0.4",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@types/react": "^18.3.17",
|
||||
"@types/react-dom": "^18.3.5",
|
||||
@ -2204,6 +2207,57 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-alert-dialog": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.6.tgz",
|
||||
"integrity": "sha512-p4XnPqgej8sZAAReCAKgz1REYZEBLR8hU9Pg27wFnCWIMc8g1ccCs0FjBcy05V15VTu8pAePw/VDYeOm/uZ6yQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.1",
|
||||
"@radix-ui/react-compose-refs": "1.1.1",
|
||||
"@radix-ui/react-context": "1.1.1",
|
||||
"@radix-ui/react-dialog": "1.1.6",
|
||||
"@radix-ui/react-primitive": "2.0.2",
|
||||
"@radix-ui/react-slot": "1.1.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-primitive": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
|
||||
"integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-slot": "1.1.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-collapsible": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.2.tgz",
|
||||
@ -2260,6 +2314,24 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz",
|
||||
"integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-compose-refs": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
|
||||
@ -2291,25 +2363,99 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-dialog": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.4.tgz",
|
||||
"integrity": "sha512-Ur7EV1IwQGCyaAuyDRiOLA5JIUZxELJljF+MbM/2NC0BYwfuRrbpS30BiQBJrVruscgUkieKkqXYDOoByaxIoA==",
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.6.tgz",
|
||||
"integrity": "sha512-/IVhJV5AceX620DUJ4uYVMymzsipdKBzo3edo+omeskCKGm9FRHM0ebIdbPnlQVJqyuHbuBltQUOG2mOTq2IYw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.1",
|
||||
"@radix-ui/react-compose-refs": "1.1.1",
|
||||
"@radix-ui/react-context": "1.1.1",
|
||||
"@radix-ui/react-dismissable-layer": "1.1.3",
|
||||
"@radix-ui/react-dismissable-layer": "1.1.5",
|
||||
"@radix-ui/react-focus-guards": "1.1.1",
|
||||
"@radix-ui/react-focus-scope": "1.1.1",
|
||||
"@radix-ui/react-focus-scope": "1.1.2",
|
||||
"@radix-ui/react-id": "1.1.0",
|
||||
"@radix-ui/react-portal": "1.1.3",
|
||||
"@radix-ui/react-portal": "1.1.4",
|
||||
"@radix-ui/react-presence": "1.1.2",
|
||||
"@radix-ui/react-primitive": "2.0.1",
|
||||
"@radix-ui/react-slot": "1.1.1",
|
||||
"@radix-ui/react-primitive": "2.0.2",
|
||||
"@radix-ui/react-slot": "1.1.2",
|
||||
"@radix-ui/react-use-controllable-state": "1.1.0",
|
||||
"aria-hidden": "^1.1.1",
|
||||
"react-remove-scroll": "^2.6.1"
|
||||
"aria-hidden": "^1.2.4",
|
||||
"react-remove-scroll": "^2.6.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz",
|
||||
"integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.1",
|
||||
"@radix-ui/react-compose-refs": "1.1.1",
|
||||
"@radix-ui/react-primitive": "2.0.2",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||
"@radix-ui/react-use-escape-keydown": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-portal": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz",
|
||||
"integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.0.2",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
|
||||
"integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-slot": "1.1.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
@ -2384,13 +2530,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-focus-scope": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.1.tgz",
|
||||
"integrity": "sha512-01omzJAYRxXdG2/he/+xy+c8a8gCydoQ1yOxnWNcRhrrBW5W+RQJ22EK1SaO8tb3WoUsuEw7mJjBozPzihDFjA==",
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.2.tgz",
|
||||
"integrity": "sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.1",
|
||||
"@radix-ui/react-primitive": "2.0.1",
|
||||
"@radix-ui/react-primitive": "2.0.2",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@ -2408,6 +2554,29 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-primitive": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
|
||||
"integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-slot": "1.1.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-id": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz",
|
||||
@ -2497,6 +2666,24 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz",
|
||||
"integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-progress": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.1.tgz",
|
||||
@ -2553,9 +2740,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-slot": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz",
|
||||
"integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==",
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
|
||||
"integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.1"
|
||||
@ -3133,6 +3320,49 @@
|
||||
"react": "^16.14.0 || 17.x || 18.x || 19.x"
|
||||
}
|
||||
},
|
||||
"node_modules/@shadcn/ui": {
|
||||
"version": "0.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@shadcn/ui/-/ui-0.0.4.tgz",
|
||||
"integrity": "sha512-0dtu/5ApsOZ24qgaZwtif8jVwqol7a4m1x5AxPuM1k5wxhqU7t/qEfBGtaSki1R8VlbTQfCj5PAlO45NKCa7Gg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chalk": "5.2.0",
|
||||
"commander": "^10.0.0",
|
||||
"execa": "^7.0.0",
|
||||
"fs-extra": "^11.1.0",
|
||||
"node-fetch": "^3.3.0",
|
||||
"ora": "^6.1.2",
|
||||
"prompts": "^2.4.2",
|
||||
"zod": "^3.20.2"
|
||||
},
|
||||
"bin": {
|
||||
"ui": "dist/index.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@shadcn/ui/node_modules/chalk": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz",
|
||||
"integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^12.17.0 || ^14.13 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@shadcn/ui/node_modules/commander": {
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
|
||||
"integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@sinclair/typebox": {
|
||||
"version": "0.27.8",
|
||||
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
|
||||
@ -8229,16 +8459,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-remove-scroll": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.2.tgz",
|
||||
"integrity": "sha512-KmONPx5fnlXYJQqC62Q+lwIeAk64ws/cUw6omIumRzMRPqgnYqhSSti99nbj0Ry13bv7dF+BKn7NB+OqkdZGTw==",
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.3.tgz",
|
||||
"integrity": "sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-remove-scroll-bar": "^2.3.7",
|
||||
"react-style-singleton": "^2.2.1",
|
||||
"react-style-singleton": "^2.2.3",
|
||||
"tslib": "^2.1.0",
|
||||
"use-callback-ref": "^1.3.3",
|
||||
"use-sidecar": "^1.1.2"
|
||||
"use-sidecar": "^1.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
|
||||
@ -23,8 +23,10 @@
|
||||
"@opentelemetry/sdk-metrics": "^1.30.1",
|
||||
"@opentelemetry/sdk-trace-web": "^1.30.1",
|
||||
"@radix-ui/react-accordion": "^1.2.2",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.6",
|
||||
"@radix-ui/react-dialog": "^1.1.4",
|
||||
"@radix-ui/react-progress": "^1.1.1",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-tabs": "^1.1.2",
|
||||
"@radix-ui/react-toast": "^1.2.4",
|
||||
"@sentry/react": "^8.48.0",
|
||||
@ -53,6 +55,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.9.1",
|
||||
"@shadcn/ui": "^0.0.4",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@types/react": "^18.3.17",
|
||||
"@types/react-dom": "^18.3.5",
|
||||
|
||||
139
src/components/ui/alert-dialog.tsx
Normal file
139
src/components/ui/alert-dialog.tsx
Normal file
@ -0,0 +1,139 @@
|
||||
import * as React from "react"
|
||||
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { buttonVariants } from "@/components/ui/button"
|
||||
|
||||
const AlertDialog = AlertDialogPrimitive.Root
|
||||
|
||||
const AlertDialogTrigger = AlertDialogPrimitive.Trigger
|
||||
|
||||
const AlertDialogPortal = AlertDialogPrimitive.Portal
|
||||
|
||||
const AlertDialogOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Overlay
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
))
|
||||
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
|
||||
|
||||
const AlertDialogContent = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPortal>
|
||||
<AlertDialogOverlay />
|
||||
<AlertDialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</AlertDialogPortal>
|
||||
))
|
||||
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
|
||||
|
||||
const AlertDialogHeader = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col space-y-2 text-center sm:text-left",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
AlertDialogHeader.displayName = "AlertDialogHeader"
|
||||
|
||||
const AlertDialogFooter = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
AlertDialogFooter.displayName = "AlertDialogFooter"
|
||||
|
||||
const AlertDialogTitle = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn("text-lg font-semibold", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
|
||||
|
||||
const AlertDialogDescription = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AlertDialogDescription.displayName =
|
||||
AlertDialogPrimitive.Description.displayName
|
||||
|
||||
const AlertDialogAction = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Action>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Action
|
||||
ref={ref}
|
||||
className={cn(buttonVariants(), className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
|
||||
|
||||
const AlertDialogCancel = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Cancel
|
||||
ref={ref}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline" }),
|
||||
"mt-2 sm:mt-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
|
||||
|
||||
export {
|
||||
AlertDialog,
|
||||
AlertDialogPortal,
|
||||
AlertDialogOverlay,
|
||||
AlertDialogTrigger,
|
||||
AlertDialogContent,
|
||||
AlertDialogHeader,
|
||||
AlertDialogFooter,
|
||||
AlertDialogTitle,
|
||||
AlertDialogDescription,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
}
|
||||
@ -7,11 +7,41 @@ import { EVENT_CATEGORIES } from '../../constants/analytics';
|
||||
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
as?: 'button' | 'span';
|
||||
trackingId: string;
|
||||
variant?: 'default' | 'primary' | 'secondary' | 'outline' | 'ghost' | 'link';
|
||||
variant?: 'default' | 'primary' | 'secondary' | 'outline' | 'ghost' | 'link' | 'destructive';
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
trackingProperties?: ButtonTrackingOptions;
|
||||
}
|
||||
|
||||
export function buttonVariants({
|
||||
variant = 'default',
|
||||
size = 'md',
|
||||
className = '',
|
||||
}: {
|
||||
variant?: ButtonProps['variant'];
|
||||
size?: ButtonProps['size'];
|
||||
className?: string;
|
||||
} = {}) {
|
||||
return cn(
|
||||
'inline-flex items-center justify-center px-4 py-2',
|
||||
'text-sm font-medium',
|
||||
'rounded-md shadow-sm',
|
||||
'transition-colors duration-200',
|
||||
'disabled:opacity-50 disabled:cursor-not-allowed',
|
||||
{
|
||||
'text-white bg-purple-600 hover:bg-purple-700': variant === 'primary' || variant === 'default',
|
||||
'text-gray-700 bg-white border border-gray-300 hover:bg-gray-50': variant === 'secondary',
|
||||
'text-purple-600 bg-transparent hover:bg-purple-50': variant === 'ghost',
|
||||
'text-purple-600 bg-transparent hover:underline': variant === 'link',
|
||||
'text-purple-600 border border-purple-600 hover:bg-purple-50': variant === 'outline',
|
||||
'text-white bg-red-600 hover:bg-red-700': variant === 'destructive',
|
||||
'px-3 py-1.5 text-sm': size === 'sm',
|
||||
'px-4 py-2 text-base': size === 'md',
|
||||
'px-6 py-3 text-lg': size === 'lg',
|
||||
},
|
||||
className
|
||||
);
|
||||
}
|
||||
|
||||
export function Button({
|
||||
as: Component = 'button',
|
||||
children,
|
||||
@ -41,29 +71,10 @@ export function Button({
|
||||
onClick?.(event);
|
||||
};
|
||||
|
||||
const baseStyles = cn(
|
||||
'inline-flex items-center justify-center px-4 py-2',
|
||||
'text-sm font-medium',
|
||||
'rounded-md shadow-sm',
|
||||
'transition-colors duration-200',
|
||||
'disabled:opacity-50 disabled:cursor-not-allowed',
|
||||
{
|
||||
'text-white bg-purple-600 hover:bg-purple-700': variant === 'primary' || variant === 'default',
|
||||
'text-gray-700 bg-white border border-gray-300 hover:bg-gray-50': variant === 'secondary',
|
||||
'text-purple-600 bg-transparent hover:bg-purple-50': variant === 'ghost',
|
||||
'text-purple-600 bg-transparent hover:underline': variant === 'link',
|
||||
'text-purple-600 border border-purple-600 hover:bg-purple-50': variant === 'outline',
|
||||
'px-3 py-1.5 text-sm': size === 'sm',
|
||||
'px-4 py-2 text-base': size === 'md',
|
||||
'px-6 py-3 text-lg': size === 'lg',
|
||||
},
|
||||
className
|
||||
);
|
||||
|
||||
return (
|
||||
<Component
|
||||
type={Component === 'button' ? type : undefined}
|
||||
className={baseStyles}
|
||||
className={buttonVariants({ variant, size, className })}
|
||||
onClick={handleClick}
|
||||
disabled={disabled}
|
||||
{...props}
|
||||
|
||||
@ -8,13 +8,7 @@ if (!supabaseUrl || !supabaseAnonKey) {
|
||||
throw new Error('Variáveis de ambiente do Supabase não configuradas')
|
||||
}
|
||||
|
||||
export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
|
||||
auth: {
|
||||
autoRefreshToken: true,
|
||||
persistSession: true,
|
||||
detectSessionInUrl: true
|
||||
}
|
||||
})
|
||||
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
|
||||
|
||||
export const generateStoryFunction = async (prompt: StoryPrompt) => {
|
||||
const { data: { session } } = await supabase.auth.getSession()
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { supabase } from '@/lib/supabase';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
@ -40,10 +40,9 @@ interface Essay {
|
||||
};
|
||||
}
|
||||
|
||||
export default function EssayAnalysisPage() {
|
||||
const router = useRouter();
|
||||
const { id } = router.query;
|
||||
const { supabase } = supabase();
|
||||
export function EssayAnalysis() {
|
||||
const navigate = useNavigate();
|
||||
const { id } = useParams();
|
||||
const [analysis, setAnalysis] = useState<EssayAnalysis | null>(null);
|
||||
const [essay, setEssay] = useState<Essay | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
@ -94,7 +93,16 @@ export default function EssayAnalysisPage() {
|
||||
return (
|
||||
<div className="container mx-auto p-6">
|
||||
<div className="flex items-center gap-4 mb-6">
|
||||
<Button variant="ghost" onClick={() => router.push(`/student-dashboard/essays/${id}`)}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => navigate(`/aluno/redacoes/${id}`)}
|
||||
trackingId="essay-analysis-back-button"
|
||||
trackingProperties={{
|
||||
action: 'back_to_essay',
|
||||
page: 'essay_analysis',
|
||||
essay_id: id
|
||||
}}
|
||||
>
|
||||
<ArrowLeft className="mr-2 h-4 w-4" />
|
||||
Voltar para redação
|
||||
</Button>
|
||||
@ -1,12 +1,22 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { supabase } from '@/lib/supabase';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { ArrowLeft, Save, Send } from 'lucide-react';
|
||||
import { ArrowLeft, Save, Send, Trash2 } from 'lucide-react';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
} from "@/components/ui/alert-dialog";
|
||||
|
||||
interface Essay {
|
||||
id: string;
|
||||
@ -30,14 +40,14 @@ interface Essay {
|
||||
};
|
||||
}
|
||||
|
||||
export default function EssayPage() {
|
||||
const router = useRouter();
|
||||
const { id } = router.query;
|
||||
const { supabase } = supabase();
|
||||
export function EssayPage() {
|
||||
const navigate = useNavigate();
|
||||
const { id } = useParams();
|
||||
const [essay, setEssay] = useState<Essay | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [wordCount, setWordCount] = useState(0);
|
||||
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
@ -117,12 +127,27 @@ export default function EssayPage() {
|
||||
if (analysisError) throw analysisError;
|
||||
|
||||
// Redireciona para a página de análise
|
||||
router.push(`/student-dashboard/essays/${essay.id}/analysis`);
|
||||
navigate(`/aluno/redacoes/${essay.id}/analise`);
|
||||
} catch (error) {
|
||||
console.error('Erro ao enviar para análise:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteEssay() {
|
||||
if (!essay) return;
|
||||
try {
|
||||
const { error } = await supabase
|
||||
.from('student_essays')
|
||||
.delete()
|
||||
.eq('id', essay.id);
|
||||
|
||||
if (error) throw error;
|
||||
navigate('/aluno/redacoes');
|
||||
} catch (error) {
|
||||
console.error('Erro ao deletar redação:', error);
|
||||
}
|
||||
}
|
||||
|
||||
if (loading) return <div>Carregando...</div>;
|
||||
if (!essay) return <div>Redação não encontrada</div>;
|
||||
|
||||
@ -134,7 +159,15 @@ export default function EssayPage() {
|
||||
<div className="container mx-auto p-6">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<div className="flex items-center gap-4">
|
||||
<Button variant="ghost" onClick={() => router.push('/student-dashboard/essays')}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => navigate('/aluno/redacoes')}
|
||||
trackingId="essay-back-to-list-button"
|
||||
trackingProperties={{
|
||||
action: 'back_to_essays_list',
|
||||
page: 'essay_editor'
|
||||
}}
|
||||
>
|
||||
<ArrowLeft className="mr-2 h-4 w-4" />
|
||||
Voltar
|
||||
</Button>
|
||||
@ -150,26 +183,58 @@ export default function EssayPage() {
|
||||
<span>•</span>
|
||||
<span>{essay.essay_genre.title}</span>
|
||||
<span>•</span>
|
||||
<Badge variant={essay.status === 'draft' ? 'secondary' : 'primary'}>
|
||||
<Badge variant={essay.status === 'draft' ? 'secondary' : 'default'}>
|
||||
{essay.status === 'draft' ? 'Rascunho' : 'Enviada'}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="outline" onClick={saveEssay} disabled={saving}>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={saveEssay}
|
||||
disabled={saving}
|
||||
trackingId="essay-save-button"
|
||||
trackingProperties={{
|
||||
action: 'save_essay',
|
||||
page: 'essay_editor',
|
||||
status: essay.status
|
||||
}}
|
||||
>
|
||||
<Save className="mr-2 h-4 w-4" />
|
||||
{saving ? 'Salvando...' : 'Salvar'}
|
||||
</Button>
|
||||
{essay.status === 'draft' && (
|
||||
<Button
|
||||
onClick={submitForAnalysis}
|
||||
disabled={!isWithinWordLimit}
|
||||
title={!isWithinWordLimit ? 'Número de palavras fora do limite' : ''}
|
||||
>
|
||||
<Send className="mr-2 h-4 w-4" />
|
||||
Enviar para análise
|
||||
</Button>
|
||||
<>
|
||||
<Button
|
||||
onClick={submitForAnalysis}
|
||||
disabled={!isWithinWordLimit}
|
||||
title={!isWithinWordLimit ? 'Número de palavras fora do limite' : ''}
|
||||
trackingId="essay-submit-analysis-button"
|
||||
trackingProperties={{
|
||||
action: 'submit_for_analysis',
|
||||
page: 'essay_editor',
|
||||
word_count: wordCount,
|
||||
within_limit: isWithinWordLimit
|
||||
}}
|
||||
>
|
||||
<Send className="mr-2 h-4 w-4" />
|
||||
Enviar para análise
|
||||
</Button>
|
||||
<Button
|
||||
variant="destructive"
|
||||
onClick={() => setShowDeleteDialog(true)}
|
||||
trackingId="essay-delete-button"
|
||||
trackingProperties={{
|
||||
action: 'delete_essay',
|
||||
page: 'essay_editor',
|
||||
status: essay.status
|
||||
}}
|
||||
>
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
Deletar
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@ -209,6 +274,23 @@ export default function EssayPage() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<AlertDialog open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Você tem certeza?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Esta ação não pode ser desfeita. Isso excluirá permanentemente sua redação.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancelar</AlertDialogCancel>
|
||||
<AlertDialogAction onClick={deleteEssay} className="bg-red-600 hover:bg-red-700">
|
||||
Deletar
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
import { useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { supabase } from '@/lib/supabase';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@ -24,15 +24,18 @@ interface EssayGenre {
|
||||
};
|
||||
}
|
||||
|
||||
export default function NewEssayPage() {
|
||||
const router = useRouter();
|
||||
const { supabase } = supabase();
|
||||
export function NewEssay() {
|
||||
const navigate = useNavigate();
|
||||
const [step, setStep] = useState<'type' | 'genre'>('type');
|
||||
const [selectedType, setSelectedType] = useState<EssayType | null>(null);
|
||||
const [types, setTypes] = useState<EssayType[]>([]);
|
||||
const [genres, setGenres] = useState<EssayGenre[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
loadTypes();
|
||||
}, []);
|
||||
|
||||
// Carregar tipos textuais
|
||||
async function loadTypes() {
|
||||
try {
|
||||
@ -69,9 +72,13 @@ export default function NewEssayPage() {
|
||||
// Criar nova redação
|
||||
async function createEssay(genreId: string) {
|
||||
try {
|
||||
const { data: { user } } = await supabase.auth.getUser();
|
||||
if (!user) throw new Error('Usuário não autenticado');
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('student_essays')
|
||||
.insert({
|
||||
student_id: user.id,
|
||||
type_id: selectedType!.id,
|
||||
genre_id: genreId,
|
||||
status: 'draft',
|
||||
@ -82,7 +89,7 @@ export default function NewEssayPage() {
|
||||
.single();
|
||||
|
||||
if (error) throw error;
|
||||
router.push(`/student-dashboard/essays/${data.id}`);
|
||||
navigate(`/aluno/redacoes/${data.id}`);
|
||||
} catch (error) {
|
||||
console.error('Erro ao criar redação:', error);
|
||||
}
|
||||
@ -156,7 +163,16 @@ export default function NewEssayPage() {
|
||||
<div className="container mx-auto p-6">
|
||||
<div className="flex items-center gap-4 mb-6">
|
||||
{step === 'genre' && (
|
||||
<Button variant="ghost" onClick={() => setStep('type')}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => setStep('type')}
|
||||
trackingId="essay-new-back-button"
|
||||
trackingProperties={{
|
||||
action: 'back_to_type_selection',
|
||||
current_step: 'genre',
|
||||
page: 'new_essay'
|
||||
}}
|
||||
>
|
||||
<ArrowLeft className="mr-2 h-4 w-4" />
|
||||
Voltar
|
||||
</Button>
|
||||
@ -1,9 +1,9 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { supabase } from '@/lib/supabase';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { PlusCircle } from 'lucide-react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
|
||||
interface Essay {
|
||||
@ -21,9 +21,8 @@ interface Essay {
|
||||
};
|
||||
}
|
||||
|
||||
export default function EssaysPage() {
|
||||
const router = useRouter();
|
||||
const { supabase } = supabase();
|
||||
export function EssaysPage() {
|
||||
const navigate = useNavigate();
|
||||
const [essays, setEssays] = useState<Essay[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
@ -53,20 +52,27 @@ export default function EssaysPage() {
|
||||
|
||||
function getStatusBadge(status: Essay['status']) {
|
||||
const statusMap = {
|
||||
draft: { label: 'Rascunho', variant: 'secondary' },
|
||||
submitted: { label: 'Enviada', variant: 'primary' },
|
||||
analyzed: { label: 'Analisada', variant: 'success' }
|
||||
draft: { label: 'Rascunho', variant: 'secondary' as const },
|
||||
submitted: { label: 'Enviada', variant: 'default' as const },
|
||||
analyzed: { label: 'Analisada', variant: 'success' as const }
|
||||
};
|
||||
|
||||
const { label, variant } = statusMap[status];
|
||||
return <Badge variant={variant as any}>{label}</Badge>;
|
||||
return <Badge variant={variant}>{label}</Badge>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="container mx-auto p-6">
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<h1 className="text-3xl font-bold">Minhas Redações</h1>
|
||||
<Button onClick={() => router.push('/student-dashboard/essays/new')}>
|
||||
<Button
|
||||
onClick={() => navigate('/aluno/redacoes/nova')}
|
||||
trackingId="essay-new-create-button"
|
||||
trackingProperties={{
|
||||
action: 'create_new_essay',
|
||||
page: 'essays_list'
|
||||
}}
|
||||
>
|
||||
<PlusCircle className="mr-2 h-4 w-4" />
|
||||
Nova Redação
|
||||
</Button>
|
||||
@ -78,7 +84,15 @@ export default function EssaysPage() {
|
||||
<Card>
|
||||
<CardContent className="flex flex-col items-center justify-center p-6">
|
||||
<p className="text-muted-foreground mb-4">Você ainda não tem nenhuma redação</p>
|
||||
<Button onClick={() => router.push('/student-dashboard/essays/new')}>
|
||||
<Button
|
||||
onClick={() => navigate('/aluno/redacoes/nova')}
|
||||
trackingId="essay-empty-create-button"
|
||||
trackingProperties={{
|
||||
action: 'create_first_essay',
|
||||
page: 'essays_list',
|
||||
context: 'empty_state'
|
||||
}}
|
||||
>
|
||||
Criar Primeira Redação
|
||||
</Button>
|
||||
</CardContent>
|
||||
@ -87,7 +101,7 @@ export default function EssaysPage() {
|
||||
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
{essays.map((essay) => (
|
||||
<Card key={essay.id} className="cursor-pointer hover:shadow-lg transition-shadow"
|
||||
onClick={() => router.push(`/student-dashboard/essays/${essay.id}`)}>
|
||||
onClick={() => navigate(`/aluno/redacoes/${essay.id}`)}>
|
||||
<CardHeader>
|
||||
<div className="flex justify-between items-start">
|
||||
<div>
|
||||
|
||||
@ -34,9 +34,9 @@ import { TextSalesLetter } from './pages/landing/TextSalesLetter';
|
||||
import { PhonicsPage } from "./pages/student-dashboard/PhonicsPage";
|
||||
import { PhonicsProgressPage } from "./pages/student-dashboard/PhonicsProgressPage";
|
||||
import { EssaysPage } from './pages/student-dashboard/essays';
|
||||
import { NewEssayPage } from './pages/student-dashboard/essays/new';
|
||||
import { EssayPage } from './pages/student-dashboard/essays/[id]';
|
||||
import { EssayAnalysisPage } from './pages/student-dashboard/essays/[id]/analysis';
|
||||
import { NewEssay } from './pages/student-dashboard/essays/NewEssay';
|
||||
import { EssayPage } from './pages/student-dashboard/essays/EssayPage';
|
||||
import { EssayAnalysis } from './pages/student-dashboard/essays/EssayAnalysis';
|
||||
|
||||
function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
@ -233,7 +233,7 @@ export const router = createBrowserRouter([
|
||||
},
|
||||
{
|
||||
path: 'nova',
|
||||
element: <NewEssayPage />,
|
||||
element: <NewEssay />,
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
@ -241,7 +241,7 @@ export const router = createBrowserRouter([
|
||||
},
|
||||
{
|
||||
path: ':id/analise',
|
||||
element: <EssayAnalysisPage />,
|
||||
element: <EssayAnalysis />,
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user