From 8f5a88788c5d9783703698c8e3d326295f06e86a Mon Sep 17 00:00:00 2001
From: 230417 <230417@epvc.pt>
Date: Wed, 6 May 2026 12:44:35 +0100
Subject: [PATCH] feat: upgrade React Navigation to v7 and redesign appointment
cards in Dashboard and Profile pages
---
package-lock.json | 159 ++++++++++++++++++--------------
package.json | 6 +-
src/pages/Dashboard.tsx | 197 +++++++++++++++++++++++++++++++---------
src/pages/Profile.tsx | 194 +++++++++++++++++++++++++++++++++------
4 files changed, 412 insertions(+), 144 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 9dde4b6..ced27b8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,9 +9,9 @@
"version": "1.0.0",
"dependencies": {
"@react-native-async-storage/async-storage": "2.2.0",
- "@react-navigation/bottom-tabs": "^6.5.11",
- "@react-navigation/native": "^6.1.9",
- "@react-navigation/native-stack": "^6.9.17",
+ "@react-navigation/bottom-tabs": "^7.15.11",
+ "@react-navigation/native": "^7.2.2",
+ "@react-navigation/native-stack": "^7.14.12",
"@supabase/supabase-js": "^2.99.1",
"expo": "~54.0.33",
"expo-constants": "~18.0.13",
@@ -71,7 +71,6 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz",
"integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.28.6",
"@babel/generator": "^7.28.6",
@@ -2973,44 +2972,46 @@
"license": "MIT"
},
"node_modules/@react-navigation/bottom-tabs": {
- "version": "6.6.1",
- "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-6.6.1.tgz",
- "integrity": "sha512-9oD4cypEBjPuaMiu9tevWGiQ4w/d6l3HNhcJ1IjXZ24xvYDSs0mqjUcdt8SWUolCvRrYc/DmNBLlT83bk0bHTw==",
+ "version": "7.15.11",
+ "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-7.15.11.tgz",
+ "integrity": "sha512-+WtNbd6fJgbViDNjmBUUP7eTgGH+zBtrl3jHuNnfUfXTs9YGuI5q3SiHIc9a5gY3voBOxbOXEiHJyW4xea7nAw==",
"license": "MIT",
"dependencies": {
- "@react-navigation/elements": "^1.3.31",
+ "@react-navigation/elements": "^2.9.15",
"color": "^4.2.3",
- "warn-once": "^0.1.0"
+ "sf-symbols-typescript": "^2.1.0"
},
"peerDependencies": {
- "@react-navigation/native": "^6.0.0",
- "react": "*",
+ "@react-navigation/native": "^7.2.2",
+ "react": ">= 18.2.0",
"react-native": "*",
- "react-native-safe-area-context": ">= 3.0.0",
- "react-native-screens": ">= 3.0.0"
+ "react-native-safe-area-context": ">= 4.0.0",
+ "react-native-screens": ">= 4.0.0"
}
},
"node_modules/@react-navigation/core": {
- "version": "6.4.17",
- "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-6.4.17.tgz",
- "integrity": "sha512-Nd76EpomzChWAosGqWOYE3ItayhDzIEzzZsT7PfGcRFDgW5miHV2t4MZcq9YIK4tzxZjVVpYbIynOOQQd1e0Cg==",
+ "version": "7.17.2",
+ "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.17.2.tgz",
+ "integrity": "sha512-Rt2OZwcgOmjv401uLGAKaRM6xo0fiBce/A7LfRHI1oe5FV+KooWcgAoZ2XOtgKj6UzVMuQWt3b2e6rxo/mDJRA==",
"license": "MIT",
"dependencies": {
- "@react-navigation/routers": "^6.1.9",
+ "@react-navigation/routers": "^7.5.3",
"escape-string-regexp": "^4.0.0",
- "nanoid": "^3.1.23",
+ "fast-deep-equal": "^3.1.3",
+ "nanoid": "^3.3.11",
"query-string": "^7.1.3",
- "react-is": "^16.13.0",
- "use-latest-callback": "^0.2.1"
+ "react-is": "^19.1.0",
+ "use-latest-callback": "^0.2.4",
+ "use-sync-external-store": "^1.5.0"
},
"peerDependencies": {
- "react": "*"
+ "react": ">= 18.2.0"
}
},
"node_modules/@react-navigation/core/node_modules/nanoid": {
- "version": "3.3.11",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
- "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "version": "3.3.12",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
+ "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
"funding": [
{
"type": "github",
@@ -3026,49 +3027,62 @@
}
},
"node_modules/@react-navigation/elements": {
- "version": "1.3.31",
- "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.31.tgz",
- "integrity": "sha512-bUzP4Awlljx5RKEExw8WYtif8EuQni2glDaieYROKTnaxsu9kEIA515sXQgUDZU4Ob12VoL7+z70uO3qrlfXcQ==",
+ "version": "2.9.15",
+ "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.9.15.tgz",
+ "integrity": "sha512-cyz/pPiyyC6gaTVLsGFc1g0MYgrmuCFqklAWGXMWPscr5YU3ui94vPI4vnZwcsEy0T758TQWLzmS5XudZeRKcA==",
"license": "MIT",
+ "dependencies": {
+ "color": "^4.2.3",
+ "use-latest-callback": "^0.2.4",
+ "use-sync-external-store": "^1.5.0"
+ },
"peerDependencies": {
- "@react-navigation/native": "^6.0.0",
- "react": "*",
+ "@react-native-masked-view/masked-view": ">= 0.2.0",
+ "@react-navigation/native": "^7.2.2",
+ "react": ">= 18.2.0",
"react-native": "*",
- "react-native-safe-area-context": ">= 3.0.0"
+ "react-native-safe-area-context": ">= 4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@react-native-masked-view/masked-view": {
+ "optional": true
+ }
}
},
"node_modules/@react-navigation/native": {
- "version": "6.1.18",
- "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-6.1.18.tgz",
- "integrity": "sha512-mIT9MiL/vMm4eirLcmw2h6h/Nm5FICtnYSdohq4vTLA2FF/6PNhByM7s8ffqoVfE5L0uAa6Xda1B7oddolUiGg==",
+ "version": "7.2.2",
+ "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.2.2.tgz",
+ "integrity": "sha512-kem1Ko2BcbAjmbQIv66dNmr6EtfDut3QU0qjsVhMnLLhktwyXb6FzZYp8gTrUb6AvkAbaJoi+BF5Pl55pAUa5w==",
"license": "MIT",
- "peer": true,
"dependencies": {
- "@react-navigation/core": "^6.4.17",
+ "@react-navigation/core": "^7.17.2",
"escape-string-regexp": "^4.0.0",
"fast-deep-equal": "^3.1.3",
- "nanoid": "^3.1.23"
+ "nanoid": "^3.3.11",
+ "use-latest-callback": "^0.2.4"
},
"peerDependencies": {
- "react": "*",
+ "react": ">= 18.2.0",
"react-native": "*"
}
},
"node_modules/@react-navigation/native-stack": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-6.11.0.tgz",
- "integrity": "sha512-U5EcUB9Q2NQspCFwYGGNJm0h6wBCOv7T30QjndmvlawLkNt7S7KWbpWyxS9XBHSIKF57RgWjfxuJNTgTstpXxw==",
+ "version": "7.14.12",
+ "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-7.14.12.tgz",
+ "integrity": "sha512-dUfpkrVeVKKV8iqXsmoUp3Rv0iH3YaB3eZwScru/FlcqAp/r3/qA6zEXkGX9hZK+/ziWAPFrf1frBSNbgOYSFQ==",
"license": "MIT",
"dependencies": {
- "@react-navigation/elements": "^1.3.31",
- "warn-once": "^0.1.0"
+ "@react-navigation/elements": "^2.9.15",
+ "color": "^4.2.3",
+ "sf-symbols-typescript": "^2.1.0",
+ "warn-once": "^0.1.1"
},
"peerDependencies": {
- "@react-navigation/native": "^6.0.0",
- "react": "*",
+ "@react-navigation/native": "^7.2.2",
+ "react": ">= 18.2.0",
"react-native": "*",
- "react-native-safe-area-context": ">= 3.0.0",
- "react-native-screens": ">= 3.0.0"
+ "react-native-safe-area-context": ">= 4.0.0",
+ "react-native-screens": ">= 4.0.0"
}
},
"node_modules/@react-navigation/native/node_modules/nanoid": {
@@ -3090,18 +3104,18 @@
}
},
"node_modules/@react-navigation/routers": {
- "version": "6.1.9",
- "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-6.1.9.tgz",
- "integrity": "sha512-lTM8gSFHSfkJvQkxacGM6VJtBt61ip2XO54aNfswD+KMw6eeZ4oehl7m0me3CR9hnDE4+60iAZR8sAhvCiI3NA==",
+ "version": "7.5.3",
+ "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.5.3.tgz",
+ "integrity": "sha512-1tJHg4KKRJuQ1/EvJxatrMef3NZXEPzwUIUZ3n1yJ2t7Q97siwRtbynRpQG9/69ebbtiZ8W3ScOZF/OmhvM4Rg==",
"license": "MIT",
"dependencies": {
- "nanoid": "^3.1.23"
+ "nanoid": "^3.3.11"
}
},
"node_modules/@react-navigation/routers/node_modules/nanoid": {
- "version": "3.3.11",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
- "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "version": "3.3.12",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
+ "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
"funding": [
{
"type": "github",
@@ -3334,9 +3348,8 @@
"version": "19.1.17",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.17.tgz",
"integrity": "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==",
- "devOptional": true,
+ "dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"csstype": "^3.0.2"
}
@@ -4034,7 +4047,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -4497,7 +4509,7 @@
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
- "devOptional": true,
+ "dev": true,
"license": "MIT"
},
"node_modules/debug": {
@@ -4806,7 +4818,6 @@
"resolved": "https://registry.npmjs.org/expo/-/expo-54.0.33.tgz",
"integrity": "sha512-3yOEfAKqo+gqHcV8vKcnq0uA5zxlohnhA3fu4G43likN8ct5ZZ3LjAh9wDdKteEkoad3tFPvwxmXW711S5OHUw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/runtime": "^7.20.0",
"@expo/cli": "54.0.23",
@@ -4945,7 +4956,6 @@
"resolved": "https://registry.npmjs.org/expo-font/-/expo-font-14.0.11.tgz",
"integrity": "sha512-ga0q61ny4s/kr4k8JX9hVH69exVSIfcIc19+qZ7gt71Mqtm7xy2c6kwsPTCyhBW2Ro5yXTT8EaZOpuRi35rHbg==",
"license": "MIT",
- "peer": true,
"dependencies": {
"fontfaceobserver": "^2.1.0"
},
@@ -8040,7 +8050,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -8060,7 +8069,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
"license": "MIT",
- "peer": true,
"dependencies": {
"scheduler": "^0.26.0"
},
@@ -8081,9 +8089,9 @@
}
},
"node_modules/react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "version": "19.2.5",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.5.tgz",
+ "integrity": "sha512-Dn0t8IQhCmeIT3wu+Apm1/YVsJXsGWi6k4sPdnBIdqMVtHtv0IGi6dcpNpNkNac0zB2uUAqNX3MHzN8c+z2rwQ==",
"license": "MIT"
},
"node_modules/react-native": {
@@ -8091,7 +8099,6 @@
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.81.5.tgz",
"integrity": "sha512-1w+/oSjEXZjMqsIvmkCRsOc8UBYv163bTWKTI8+1mxztvQPhCRYGTvZ/PL1w16xXHneIj/SLGfxWg2GWN2uexw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@jest/create-cache-key-function": "^29.7.0",
"@react-native/assets-registry": "0.81.5",
@@ -8159,7 +8166,6 @@
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.2.tgz",
"integrity": "sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg==",
"license": "MIT",
- "peer": true,
"peerDependencies": {
"react": "*",
"react-native": "*"
@@ -8170,7 +8176,6 @@
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.16.0.tgz",
"integrity": "sha512-yIAyh7F/9uWkOzCi1/2FqvNvK6Wb9Y1+Kzn16SuGfN9YFJDTbwlzGRvePCNTOX0recpLQF3kc2FmvMUhyTCH1Q==",
"license": "MIT",
- "peer": true,
"dependencies": {
"react-freeze": "^1.0.0",
"react-native-is-edge-to-edge": "^1.2.1",
@@ -8302,7 +8307,6 @@
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
"integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -8729,6 +8733,15 @@
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
"license": "ISC"
},
+ "node_modules/sf-symbols-typescript": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/sf-symbols-typescript/-/sf-symbols-typescript-2.2.0.tgz",
+ "integrity": "sha512-TPbeg0b7ylrswdGCji8FRGFAKuqbpQlLbL8SOle3j1iHSs5Ob5mhvMAxWN2UItOjgALAB5Zp3fmMfj8mbWvXKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -9262,7 +9275,6 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=12"
},
@@ -9488,6 +9500,15 @@
"react": ">=16.8"
}
},
+ "node_modules/use-sync-external-store": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
+ "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/util": {
"version": "0.12.5",
"resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
diff --git a/package.json b/package.json
index aa3a2f8..1b4bc7d 100644
--- a/package.json
+++ b/package.json
@@ -10,9 +10,9 @@
},
"dependencies": {
"@react-native-async-storage/async-storage": "2.2.0",
- "@react-navigation/bottom-tabs": "^6.5.11",
- "@react-navigation/native": "^6.1.9",
- "@react-navigation/native-stack": "^6.9.17",
+ "@react-navigation/bottom-tabs": "^7.15.11",
+ "@react-navigation/native": "^7.2.2",
+ "@react-navigation/native-stack": "^7.14.12",
"@supabase/supabase-js": "^2.99.1",
"expo": "~54.0.33",
"expo-constants": "~18.0.13",
diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx
index 81d9093..326732d 100644
--- a/src/pages/Dashboard.tsx
+++ b/src/pages/Dashboard.tsx
@@ -303,45 +303,64 @@ export default function Dashboard() {
)}
{activeTab === 'appointments' && (
-
+
{activeAppointments.length > 0 ? (
activeAppointments.map((a) => {
const svc = shop.services.find((s) => s.id === a.serviceId);
const barber = shop.barbers.find((b) => b.id === a.barberId);
+
+ const dateParts = a.date.split(' ');
+ const dateObj = new Date(dateParts[0]);
+ const time = dateParts[1] || '';
+ const day = dateObj.getDate();
+ const monthNames = ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'];
+ const month = monthNames[dateObj.getMonth()] || '';
+
return (
-
-
-
- {svc?.name ?? 'Serviço'}
- {barber?.name} · {a.date}
-
-
- {a.status}
-
-
-
- Alterar status:
-
- {['pendente', 'confirmado', 'concluido', 'cancelado'].map((s) => (
-
- ))}
+
+
+ {day}
+ {month}
+
+ {time}
-
+
+
+
+ {svc?.name ?? 'Serviço'}
+ {barber?.name} · {currency(a.total)}
+
+
+ {a.status}
+
+
+
+
+ Alterar status:
+
+ {['pendente', 'confirmado', 'concluido', 'cancelado'].map((s) => (
+
+ ))}
+
+
+
+
);
})
) : (
-
- Nenhum agendamento ativo
-
+
+ 📅
+ Nenhum agendamento ativo.
+
)}
)}
@@ -384,31 +403,48 @@ export default function Dashboard() {
)}
{activeTab === 'history' && (
-
+
Histórico de Agendamentos
{historyAppointments.length > 0 ? (
historyAppointments.map((a) => {
const svc = shop.services.find((s) => s.id === a.serviceId);
const barber = shop.barbers.find((b) => b.id === a.barberId);
+
+ const dateParts = a.date.split(' ');
+ const dateObj = new Date(dateParts[0]);
+ const time = dateParts[1] || '';
+ const day = dateObj.getDate();
+ const monthNames = ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'];
+ const month = monthNames[dateObj.getMonth()] || '';
+
return (
-
-
-
- {svc?.name ?? 'Serviço'}
- {barber?.name ?? 'Barbeiro'} · {a.date}
- {currency(a.total)}
+
+
+ {day}
+ {month}
+
+ {time}
-
- {a.status === 'concluido' ? 'Concluído' : 'Cancelado'}
-
-
+
+
+
+ {svc?.name ?? 'Serviço'}
+ {barber?.name ?? 'Barbeiro'} · {currency(a.total)}
+
+
+ {a.status === 'concluido' ? 'Concluído' : 'Cancelado'}
+
+
+
+
);
})
) : (
-
+
+ 📅
Ainda não há registos concluídos ou cancelados.
-
+
)}
)}
@@ -850,4 +886,81 @@ const styles = StyleSheet.create({
padding: 24,
alignItems: 'center',
},
+ agendaContainer: {
+ gap: 12,
+ },
+ agendaTicket: {
+ flexDirection: 'row',
+ backgroundColor: '#fff',
+ borderRadius: 24,
+ overflow: 'hidden',
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 4 },
+ shadowOpacity: 0.05,
+ shadowRadius: 10,
+ elevation: 3,
+ marginBottom: 8,
+ },
+ agendaDateBox: {
+ backgroundColor: '#0f172a',
+ paddingVertical: 16,
+ paddingHorizontal: 12,
+ alignItems: 'center',
+ justifyContent: 'center',
+ minWidth: 85,
+ },
+ agendaDay: {
+ color: '#fff',
+ fontSize: 28,
+ fontWeight: '900',
+ lineHeight: 32,
+ },
+ agendaMonth: {
+ color: '#818cf8',
+ fontSize: 14,
+ fontWeight: '800',
+ textTransform: 'uppercase',
+ marginBottom: 8,
+ },
+ agendaTimeWrapper: {
+ backgroundColor: 'rgba(255,255,255,0.1)',
+ paddingHorizontal: 8,
+ paddingVertical: 4,
+ borderRadius: 8,
+ },
+ agendaTime: {
+ color: '#fff',
+ fontSize: 12,
+ fontWeight: '700',
+ },
+ agendaContent: {
+ flex: 1,
+ padding: 16,
+ justifyContent: 'center',
+ },
+ agendaHeader: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'flex-start',
+ marginBottom: 4,
+ },
+ agendaShopName: {
+ fontSize: 16,
+ fontWeight: '900',
+ color: '#0f172a',
+ marginRight: 8,
+ },
+ emptyAgendaState: {
+ alignItems: 'center',
+ padding: 40,
+ backgroundColor: '#fff',
+ borderRadius: 28,
+ borderWidth: 1,
+ borderColor: '#e2e8f0',
+ borderStyle: 'dashed',
+ gap: 16,
+ },
+ emptyAgendaIcon: {
+ fontSize: 48,
+ },
});
diff --git a/src/pages/Profile.tsx b/src/pages/Profile.tsx
index 6c84793..19ae346 100644
--- a/src/pages/Profile.tsx
+++ b/src/pages/Profile.tsx
@@ -232,44 +232,70 @@ export default function Profile() {
)}
{activeTab === 'agenda' && (
-
- Minha Agenda
+
+ Próximos Agendamentos
{myAppointments.length ? myAppointments.map((appointment) => {
const shop = shops.find((s) => s.id === appointment.shopId);
const service = shop?.services.find((s) => s.id === appointment.serviceId);
const canReview = appointment.status === 'concluido' && !reviewedAppointments.has(appointment.id);
+
+ const dateParts = appointment.date.split(' ');
+ const dateObj = new Date(dateParts[0]);
+ const time = dateParts[1] || '';
+ const day = dateObj.getDate();
+ const monthNames = ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'];
+ const month = monthNames[dateObj.getMonth()] || '';
return (
-
-
- {shop?.name || 'Barbearia'}
- {statusLabel[appointment.status]}
+
+
+ {day}
+ {month}
+
+ {time}
+
- {appointment.date}
- {!!service && {service.name} · {service.duration} min}
- {currency(appointment.total)}
- {canReview ? (
-
- ) : appointment.status === 'concluido' ? (
- Avaliado
- ) : null}
-
+
+
+ {shop?.name || 'Barbearia'}
+
+ {statusLabel[appointment.status]}
+
+
+ {!!service && {service.name}}
+
+ {currency(appointment.total)}
+ {canReview ? (
+ {
+ setReviewTarget({
+ appointmentId: appointment.id,
+ shopId: appointment.shopId,
+ shopName: shop?.name || 'Barbearia',
+ });
+ }}
+ >
+ Avaliar
+
+ ) : appointment.status === 'concluido' ? (
+ ✓ Avaliado
+ ) : null}
+
+
+
);
}) : (
-
- Sem agendamentos futuros.
-
+
+ 📅
+ Não tens marcações agendadas.
+
+
)}
)}
@@ -521,6 +547,114 @@ const styles = StyleSheet.create({
fontSize: 12,
fontWeight: '900',
textTransform: 'uppercase',
- marginTop: 10,
+ },
+ agendaContainer: {
+ gap: 12,
+ },
+ agendaTicket: {
+ flexDirection: 'row',
+ backgroundColor: '#fff',
+ borderRadius: 24,
+ overflow: 'hidden',
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 4 },
+ shadowOpacity: 0.05,
+ shadowRadius: 10,
+ elevation: 3,
+ marginBottom: 8,
+ },
+ agendaDateBox: {
+ backgroundColor: '#0f172a',
+ paddingVertical: 16,
+ paddingHorizontal: 12,
+ alignItems: 'center',
+ justifyContent: 'center',
+ minWidth: 85,
+ },
+ agendaDay: {
+ color: '#fff',
+ fontSize: 28,
+ fontWeight: '900',
+ lineHeight: 32,
+ },
+ agendaMonth: {
+ color: '#818cf8',
+ fontSize: 14,
+ fontWeight: '800',
+ textTransform: 'uppercase',
+ marginBottom: 8,
+ },
+ agendaTimeWrapper: {
+ backgroundColor: 'rgba(255,255,255,0.1)',
+ paddingHorizontal: 8,
+ paddingVertical: 4,
+ borderRadius: 8,
+ },
+ agendaTime: {
+ color: '#fff',
+ fontSize: 12,
+ fontWeight: '700',
+ },
+ agendaContent: {
+ flex: 1,
+ padding: 16,
+ justifyContent: 'center',
+ },
+ agendaHeader: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'flex-start',
+ marginBottom: 4,
+ },
+ agendaShopName: {
+ fontSize: 16,
+ fontWeight: '900',
+ color: '#0f172a',
+ flex: 1,
+ marginRight: 8,
+ },
+ agendaBadge: {
+ transform: [{ scale: 0.9 }],
+ },
+ agendaService: {
+ fontSize: 14,
+ color: '#64748b',
+ fontWeight: '600',
+ marginBottom: 12,
+ },
+ agendaFooter: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ },
+ agendaTotal: {
+ fontSize: 16,
+ fontWeight: '900',
+ color: '#6366f1',
+ },
+ reviewMiniButton: {
+ backgroundColor: '#818cf8',
+ paddingHorizontal: 12,
+ paddingVertical: 6,
+ borderRadius: 12,
+ },
+ reviewMiniButtonText: {
+ color: '#fff',
+ fontSize: 11,
+ fontWeight: '900',
+ textTransform: 'uppercase',
+ },
+ emptyAgendaState: {
+ alignItems: 'center',
+ padding: 40,
+ backgroundColor: '#fff',
+ borderRadius: 28,
+ borderWidth: 1,
+ borderColor: '#e2e8f0',
+ borderStyle: 'dashed',
+ gap: 16,
+ },
+ emptyAgendaIcon: {
+ fontSize: 48,
},
});