diff --git a/api/app/Http/Controllers/AuthController.php b/api/app/Http/Controllers/AuthController.php index 957ed11..a7cf1b2 100644 --- a/api/app/Http/Controllers/AuthController.php +++ b/api/app/Http/Controllers/AuthController.php @@ -58,12 +58,20 @@ class AuthController extends Controller return response()->json(['message' => 'Nickname already registered'], 409); } + $avatarFilename = null; + + if ($request->hasFile('photo_avatar_filename')) { + $file = $request->file('photo_avatar_filename'); + $path = $file->store('photos_avatars', 'public'); + $avatarFilename = basename($path); + } + $user = User::create([ 'email' => $request->email, 'nickname' => $request->nickname, 'name' => $request->name, 'password' => bcrypt($request->password), - 'photo_avatar_filename' => $request->photo, + 'photo_avatar_filename' => $avatarFilename, 'type' => 'P', 'blocked' => false, 'coins_balance' => 10, diff --git a/api/app/Http/Requests/RegisterRequest.php b/api/app/Http/Requests/RegisterRequest.php index 5c0b21f..4db263e 100644 --- a/api/app/Http/Requests/RegisterRequest.php +++ b/api/app/Http/Requests/RegisterRequest.php @@ -26,7 +26,7 @@ class RegisterRequest extends FormRequest 'nickname' => 'required|string|max:255', 'name' => 'required|string|max:255', 'password' => 'required|string|min:3', - 'photo' => 'nullable|string', + 'photo' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048', ]; } } diff --git a/api/sample-requests.http b/api/sample-requests.http index 6c83b44..930be4c 100644 --- a/api/sample-requests.http +++ b/api/sample-requests.http @@ -1,6 +1,6 @@ ### Get All Students (Login) # @name login -POST http://localhost:8000/api/login +POST http://localhost:8000/api/v1/login Content-Type: application/json Accept: application/json @@ -9,11 +9,24 @@ Accept: application/json "password": "123" } -### Capture the token +### Capture the token & id @token = {{login.response.body.token}} +@id = {{login.response.body.user.id}} ### Get All matches -GET http://localhost:8000/api/matches +GET http://localhost:8000/api/v1/matches +Content-Type: application/json +Accept: application/json +Authorization: Bearer {{token}} + +### Get me user +GET http://localhost:8000/api/v1/users/me +Content-Type: application/json +Accept: application/json +Authorization: Bearer {{token}} + +### Get me matches +GET http://localhost:8000/api/v1/users/{{id}}/matches Content-Type: application/json Accept: application/json Authorization: Bearer {{token}} \ No newline at end of file diff --git a/frontend/src/components/layout/NavBar.vue b/frontend/src/components/layout/NavBar.vue index 015f987..facc2e0 100644 --- a/frontend/src/components/layout/NavBar.vue +++ b/frontend/src/components/layout/NavBar.vue @@ -22,13 +22,23 @@ - - - Logout + + +
+ $ +
+ + + {{ coins }} Coins +
Profile + + Logout +
@@ -46,16 +56,20 @@ import { NavigationMenuTrigger, } from '@/components/ui/navigation-menu' import router from '@/router'; +import { ref, watch } from 'vue'; +import { useUserStore } from '@/stores/user'; + const emits = defineEmits(['logout']) const { userLoggedIn } = defineProps(['userLoggedIn']) +const coins = ref(0); const biscaStore = useBiscaStore() const logoutClickHandler = () => { if (biscaStore.isGameRunning) { const confirmLogout = window.confirm( - '⚠️ Jogo em Progresso!\n\nSe fizeres Logout agora, perderás o jogo atual e serás considerado PERDEDOR.\n\nQueres mesmo sair?' + 'If you leave now this game will count as "FORFEIT". Are you sure you want to logout?' ) if (!confirmLogout) return @@ -67,7 +81,25 @@ const logoutClickHandler = () => { } emits('logout') - - router.push({ name: 'home' }) + router.push('/login') } + +const fetchUserCoins = async () => { + if (userLoggedIn) { + try { + const response = await useUserStore().getCoins() + coins.value = response.data?.coins || 0 + } catch (error) { + console.error('Error fetching user coins', error) + } + } +} + +watch(() => userLoggedIn, async (isLoggedIn) => { + if (isLoggedIn) { + await fetchUserCoins() + } else { + coins.value = 0 + } +}, { immediate: true }) \ No newline at end of file diff --git a/frontend/src/pages/login/LoginPage.vue b/frontend/src/pages/login/LoginPage.vue index 1fd8457..004b521 100644 --- a/frontend/src/pages/login/LoginPage.vue +++ b/frontend/src/pages/login/LoginPage.vue @@ -44,7 +44,7 @@
Don't have an account? - + Sign up
diff --git a/frontend/src/pages/register/RegisterPage.vue b/frontend/src/pages/register/RegisterPage.vue new file mode 100644 index 0000000..cc6de8a --- /dev/null +++ b/frontend/src/pages/register/RegisterPage.vue @@ -0,0 +1,151 @@ + + + \ No newline at end of file diff --git a/frontend/src/pages/user/UserPage.vue b/frontend/src/pages/user/UserPage.vue index db6654f..88ce40e 100644 --- a/frontend/src/pages/user/UserPage.vue +++ b/frontend/src/pages/user/UserPage.vue @@ -9,57 +9,55 @@ -
+
- - - + + +

Oops! Something went wrong

{{ error }}

-
-
+
- -
+ +
{{ authStore.currentUser.name.charAt(0).toUpperCase() }}
- - +

{{ authStore.currentUser.name }}

@{{ authStore.currentUser.nickname }}

-
+
- + $ {{ authStore.currentUser.coins_balance }} coins @@ -71,26 +69,32 @@
+ +
@@ -101,8 +105,8 @@
- - + +
@@ -114,12 +118,13 @@
- - + +
- +

{{ authStore.currentUser.type === 'P' ? 'Player' : 'Other' }}

@@ -127,14 +132,15 @@
- - - - + + + +
- +

{{ formatDate(authStore.currentUser.created_at) }}

@@ -142,29 +148,32 @@
- - + +

- + {{ authStore.currentUser.blocked ? 'Blocked' : 'Active' }}

-
+
- - + +
- +

{{ formatDate(authStore.currentUser.email_verified_at) }}

@@ -172,12 +181,13 @@
- - + +
- +

{{ formatDate(authStore.currentUser.updated_at) }}

@@ -189,94 +199,250 @@
- +
- +
- -
-
+
{{ profileMessage }}
+ +
+
+
+ No transactions yet. +
+
+ +
+
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+ +
+ +
+
+ + + - +
+ +
+
+ {{ transaction.type }} Payment +
+
+ {{ new Date(transaction.created_at).toLocaleDateString() }} • {{ new + Date(transaction.created_at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) }} +
+
+
+ +
+
+ {{ transaction.type === 'credit' ? '+' : '-' }}${{ transaction.amount.toLocaleString() }} +
+
+ {{ transaction.id.split('_')[0] }} +
+
+
+ +
+ Loading + more... +
+
+
+
+ + +
+
+
+ No games played yet. +
+
+ +
+
+ + +
+ +
+ + +
+ + + +
+
+ +
+ + + +
+
+
+ +
+ +
+
+
+
+ {{ game.outcome }} +
+
+
vs {{ game.opponent }}
+
+ {{ game.variant }} • {{ game.duration }} +
+
+
+ +
+
{{ game.amount }} pts
+
+ {{ new Date(game.created_at).toLocaleTimeString() }} +
+
+
+ +
+ Marks: {{ game.details.marks }} + Capotes: {{ game.details.capotes }} + Bandeiras: {{ game.details.bandeiras }} +
+
+ +
+ Loading + more... +
+
+
+
+
- - Current + Password + + class="w-full px-3 py-3 border border-gray-300 text-base transition-colors focus:outline-none focus:border-black disabled:bg-gray-100 disabled:cursor-not-allowed" />
- + class="w-full px-3 py-3 border border-gray-300 text-base transition-colors focus:outline-none focus:border-black disabled:bg-gray-100 disabled:cursor-not-allowed" /> Password must be at least 8 characters long
- - Confirm New + Password + + class="w-full px-3 py-3 border border-gray-300 text-base transition-colors focus:outline-none focus:border-black disabled:bg-gray-100 disabled:cursor-not-allowed" />
- -
-
+
{{ passwordMessage }}
@@ -287,10 +453,11 @@
- - - - + + + +

Danger Zone

@@ -299,7 +466,8 @@

  • Permanently delete all your account data
  • -
  • Forfeit your current coin balance of {{ authStore.currentUser.coins_balance }} coins
  • +
  • Forfeit your current coin balance of {{ authStore.currentUser.coins_balance }} + coins
  • Remove your access to all games and matches
  • Delete your profile and all associated information
@@ -312,29 +480,21 @@ Are you absolutely sure?

- To confirm deletion, please type your email address: {{ authStore.currentUser.email }} + To confirm deletion, please type your email address: {{ + authStore.currentUser.email }}

- +
- -
@@ -345,11 +505,9 @@
-
+ @click.self="showDeleteConfirmation = false">

Final Confirmation

@@ -357,17 +515,19 @@
- - - - + + + +

This is your last chance to cancel.

- Once you click "Yes, Delete My Account", your account and all associated data will be permanently deleted. You will lose your {{ authStore.currentUser.coins_balance }} coins forever. + Once you click "Yes, Delete My Account", your account and all associated data will be permanently + deleted. You will lose your {{ authStore.currentUser.coins_balance }} coins forever.

@@ -379,18 +539,12 @@
- -
@@ -398,7 +552,8 @@
-
+

Redirecting to login...

@@ -408,10 +563,10 @@