Feat : add login button

This commit is contained in:
2024-08-01 19:48:15 +02:00
parent f9197d470e
commit 7713faa4d0
6 changed files with 215 additions and 219 deletions
+5 -5
View File
@@ -1,8 +1,8 @@
<script setup lang="ts">
import type { Player } from "~/netcode/interfaces";
import type { User } from "~/netcode/interfaces";
export interface Props {
player: Player;
user: User;
}
const props = defineProps<Props>();
@@ -12,11 +12,11 @@ const props = defineProps<Props>();
<div class="player-icon-container">
<img
class="avatar"
v-if="props.player.user.avatar"
:src="`https://cdn.discordapp.com/avatars/${props.player.user.userId}/${props.player.user.avatar}.webp`"
v-if="props.user.avatar"
:src="`https://cdn.discordapp.com/avatars/${props.user.userId}/${props.user.avatar}.webp`"
draggable="false"
/>
<b class="player-name">{{ props.player.user.username }}</b>
<b class="player-name">{{ props.user.username }}</b>
</div>
</template>
+1 -1
View File
@@ -60,7 +60,7 @@ function damage() {
Prêt!
</div> -->
<div id="player_info">
<GamePlayerIcon :player="props.player"></GamePlayerIcon>
<GamePlayerIcon :user="props.player.user"></GamePlayerIcon>
</div>
<div id="player_stats">
<!-- <template v-if="goStore.current_game?.started"> -->
+2 -19
View File
@@ -9,29 +9,12 @@ export function subscribe(endpoint: string) {
return evtSource;
}
export async function getLobby() {
export async function whoami() {
const config = useRuntimeConfig();
const req = await useFetch<Array<Game>>(config.public.endpoint + "/games", {
const req = await useFetch<User>(config.public.endpoint + "/whoami", {
credentials: "include",
server: false,
});
// await req.execute();
await req.execute();
if (req.data.value == null) {
throw new Error("Lobby answer is empty");
}
return req.data as Ref<Game[]>;
}
export async function whoami() {
const config = useRuntimeConfig();
const req = await useFetch<User>(
config.public.endpoint + "/whoami",
{
credentials: "include",
server: false,
}
);
await req.execute();
if (req.error.value && req.error.value.statusCode == 401) {
// await navigateTo(config.public.discordLoginEndpoint, {
+101 -115
View File
@@ -28,7 +28,7 @@ const {
server: false,
});
const awaitGameReady = execute();
await execute();
const containers = computed<Record<string, Container>>(() => ({
[game.value!.fireGems._id]: game.value!.fireGems,
@@ -226,25 +226,22 @@ const handlers = {
},
};
onMounted(async () => {
awaitGameReady.then(() => {
console.log(game.value);
if (game.value == null) {
navigateTo("/lobby");
onBeforeMount(async () => {
if (game.value == null) {
navigateTo("/lobby");
throw new Error("game not found");
}
focusedPlayer.value = selfPlayer.value ?? playerList.value![0];
eventSource = subscribe(`/games/${gameId}/subscribe`);
eventSource.addEventListener("message", async (message) => {
const current_game = game.value;
if (!current_game) {
throw new Error("game not found");
}
focusedPlayer.value = selfPlayer.value ?? playerList.value![0];
eventSource = subscribe(`/games/${gameId}/subscribe`);
eventSource.addEventListener("message", async (message) => {
const current_game = game.value;
if (!current_game) {
throw new Error("game not found");
}
const data = JSON.parse(message.data);
queueAction(async () => {
await handlers[data.type as keyof typeof handlers](data, current_game);
});
const data = JSON.parse(message.data);
queueAction(async () => {
await handlers[data.type as keyof typeof handlers](data, current_game);
});
});
});
@@ -294,24 +291,10 @@ function showWinnerScreen() {
isWinner.value = true;
}
// const clientStore = useClientSideStore()
// const restack_discarded_champion = (target: Card) => clientStore.findUseEffect(CardEffects.RESTACK_DISCARDED_CHAMPION, target)
// const restack_discarded_card = (target: Card) => clientStore.findUseEffect(CardEffects.RESTACK_DISCARDED_CARD, target)
// const sacrifice = (target: Card) => clientStore.findUseEffect(CardEffects.SACRIFICE, target);
function focusPlayer(p: Player) {
focusedPlayer.value = p;
}
// watch<Team>(() => goStore.current_game!.current_turn, (new_team, old_team) => {
// if (focusedPlayer.value.team != old_team) { return }
// const first_player = goStore.current_game?.players.find(p => p.team == goStore.current_game?.current_turn)
// if (!first_player) {
// return
// }
// focusPlayer(first_player)
// })
function useTokenClick(t: Effect) {
console.log(t);
useToken(game.value!._id, t._id);
@@ -332,91 +315,94 @@ onUnmounted(() => {
:isTurn="isTurn ?? false"
></AnimatedBackground>
<GameOverlayOptionsDialog></GameOverlayOptionsDialog>
<template v-if="game && focusedPlayer && playerList">
<Transition name="slide-left" mode="out-in">
<div id="stack_discard" :key="focusedPlayer?._id">
<div id="stack">
<GameCardGrouped
:container="focusedPlayer.stack"
:wrapped="true"
:hidden="true"
>
</GameCardGrouped>
</div>
<div
id="discard"
:class="{ invisible: discard_unwrapped }"
@click="() => (discard_unwrapped = true)"
>
<GameCardGrouped
:container="focusedPlayer.discard"
:wrapped="true"
@card-click="showDiscard"
:no-effects="true"
>
</GameCardGrouped>
</div>
</div>
</Transition>
<GameMarket
:game="game"
:market="game.market"
:fire_gems="game.fireGems"
:marketStack="game.marketStack"
>
</GameMarket>
<div>
<GameToken
:token="t"
v-for="t in game.currentTurn.tokens"
@useToken="useTokenClick"
></GameToken>
</div>
<div id="player_list_container">
<div id="player_list">
<GamePlayerListElement
v-for="p in playerList"
:player="p"
:game="game"
@click="focusPlayer(p)"
:focused="focusedPlayer == p"
:self="selfPlayer == p"
>
</GamePlayerListElement>
</div>
</div>
<div id="current_player">
<ClientOnly>
<template v-if="game && focusedPlayer && playerList">
<Transition name="slide-left" mode="out-in">
<GamePlayerSlot
v-if="focusedPlayer"
:player="focusedPlayer"
:game="game"
:key="focusedPlayer._id"
></GamePlayerSlot>
<div id="stack_discard" :key="focusedPlayer?._id">
<div id="stack">
<GameCardGrouped
:container="focusedPlayer.stack"
:wrapped="true"
:hidden="true"
>
</GameCardGrouped>
</div>
<div
id="discard"
:class="{ invisible: discard_unwrapped }"
@click="() => (discard_unwrapped = true)"
>
<GameCardGrouped
:container="focusedPlayer.discard"
:wrapped="true"
@card-click="showDiscard"
:no-effects="true"
>
</GameCardGrouped>
</div>
</div>
</Transition>
</div>
<GameOverlayDiscard
v-show="discard_unwrapped"
:game="game"
:player="focusedPlayer"
:discard="focusedPlayer.discard"
@close="discard_unwrapped = false"
></GameOverlayDiscard>
<GameOverlayResultDialog
:isVisible="showResults"
:won="isWinner"
:players="playerList"
@close="showResults = false"
>
</GameOverlayResultDialog>
<GamePlayerSelf
v-if="selfPlayer"
:container="selfPlayer.hand"
></GamePlayerSelf>
</template>
<GameMarket
:game="game"
:market="game.market"
:fire_gems="game.fireGems"
:marketStack="game.marketStack"
>
</GameMarket>
<div>
<GameToken
:token="t"
v-for="t in game.currentTurn.tokens"
@useToken="useTokenClick"
></GameToken>
</div>
<div id="player_list_container">
<div id="player_list">
<GamePlayerListElement
v-for="p in playerList"
:player="p"
:game="game"
@click="focusPlayer(p)"
:focused="focusedPlayer == p"
:self="selfPlayer == p"
>
</GamePlayerListElement>
</div>
</div>
<div id="current_player">
<Transition name="slide-left" mode="out-in">
<GamePlayerSlot
v-if="focusedPlayer"
:player="focusedPlayer"
:game="game"
:key="focusedPlayer._id"
></GamePlayerSlot>
</Transition>
</div>
<GameOverlayDiscard
v-show="discard_unwrapped"
:game="game"
:player="focusedPlayer"
:discard="focusedPlayer.discard"
@close="discard_unwrapped = false"
></GameOverlayDiscard>
<GameOverlayResultDialog
:isVisible="showResults"
:won="isWinner"
:players="playerList"
@close="showResults = false"
>
</GameOverlayResultDialog>
<GamePlayerSelf
v-if="selfPlayer"
:container="selfPlayer.hand"
></GamePlayerSelf>
</template>
</ClientOnly>
<!-- <LoadingScreen v-if="!loaded"></LoadingScreen> -->
</div>
</template>
+106 -79
View File
@@ -1,14 +1,22 @@
<script setup lang="ts">
// import { playSound } from '~/helpers/audioHelpers';
import { playSound } from "~/helpers/audioHelpers";
import { createGame, getLobby, subscribe } from "~/netcode";
import type { Game, Player } from "~/netcode/interfaces";
import { createGame, subscribe } from "~/netcode";
import type { Game, Player, User } from "~/netcode/interfaces";
const authStore = useAuthStore();
let eventSource: EventSource;
let games = ref<Game[]>([]);
const config = useRuntimeConfig();
const req = await useFetch<Array<Game>>(config.public.endpoint + "/games", {
credentials: "include",
server: false,
});
await req.execute();
let games = req.data;
const erika_alive = ref(true);
const router = useRouter();
@@ -19,22 +27,21 @@ function killErika() {
}
onBeforeMount(async () => {
games.value = (await getLobby()).value;
eventSource = subscribe("/games/subscribe");
eventSource.addEventListener("message", (message) => {
const data = JSON.parse(message.data);
if (data.type == "create") {
games.value.push(data);
games.value?.push(data);
} else if (data.type == "delete") {
const index = games.value.findIndex((g) => g._id == data._id);
if (index == -1) {
const index = games.value?.findIndex((g) => g._id == data._id);
if (index == -1 || !index) {
throw new Error("Couldn't delete game");
}
games.value.splice(index, 1);
games.value?.splice(index, 1);
} else if (data.type == "joinGame") {
games.value.find((g) => g._id == data.game)?.teams.push(data.team);
games.value?.find((g) => g._id == data.game)?.teams.push(data.team);
} else if (data.type == "start") {
const targetGame = games.value.find((g) => g._id == data.game);
const targetGame = games.value?.find((g) => g._id == data.game);
if (targetGame) {
targetGame.started = true;
}
@@ -49,58 +56,77 @@ onUnmounted(() => {
<template>
<div class="background">
<div class="title">Entrez dans le Royaume de Héron !</div>
<div class="middle-row">
<div class="create-game-zone">
<button @click="createGame">Create Game</button>
</div>
<div class="games-list-zone">
<div v-for="g in games">
<button
v-if="g"
@click="router.push({ path: `/game`, query: { id: g._id } })"
:class="
authStore.selfUser.userId == g.owner.userId ? 'own_game' : ''
"
>
<template
<header>
<ClientOnly>
<GamePlayerIcon
v-if="authStore.logged"
:user="(authStore.selfUser as User)"
/>
<button v-else @click="navigateTo('/login')">Login</button>
</ClientOnly>
</header>
<main>
<div class="title">Entrez dans le Royaume de Héron !</div>
<ClientOnly>
<template v-if="authStore.logged">
<div class="create-game-zone">
<button
@click="createGame"
v-if="
g.teams.every((t) =>
t.players.every(
(p) => p.user.userId !== authStore.selfUser.userId
)
)
games?.some((g) => g.owner.userId !== authStore.selfUser.userId)
"
>
SPECTATE
</template>
<template v-else>
<template v-if="!g.started"> JOIN BACK </template>
<template v-else> CONTINUE </template>
</template>
Create Game
</button>
</div>
</template>
<br />
{{
g.teams.reduce(
(prev, curr) => prev.concat(curr.players),
[] as Player[]
).length
}}
current players:<br /><span>{{
g.teams
.reduce(
<div class="games-list-zone">
<div v-for="g in games">
<button
v-if="g"
@click="router.push({ path: `/game`, query: { id: g._id } })"
:class="
authStore.selfUser.userId == g.owner.userId ? 'own_game' : ''
"
>
<template
v-if="
g.teams.every((t) =>
t.players.every(
(p) => p.user.userId !== authStore.selfUser.userId
)
)
"
>
SPECTATE
</template>
<template v-else>
<template v-if="!g.started"> JOIN BACK </template>
<template v-else> CONTINUE </template>
</template>
<br />
{{
g.teams.reduce(
(prev, curr) => prev.concat(curr.players),
[] as Player[]
)
.map((p) => p.user.username)
.join(",")
}}</span>
</button>
).length
}}
current players:<br /><span>{{
g.teams
.reduce(
(prev, curr) => prev.concat(curr.players),
[] as Player[]
)
.map((p) => p.user.username)
.join(",")
}}</span>
</button>
</div>
</div>
</div>
</div>
</ClientOnly>
</main>
<div class="overlay" v-if="erika_alive">
<div class="erika-zone">
@@ -141,9 +167,9 @@ onUnmounted(() => {
background-color: #f0f0f0;
background-image: url("https://www.pockettactics.com/wp-content/sites/pockettactics/2023/01/fire-emblem-engage-review-29.jpg");
background-size: cover;
display: flex;
flex-direction: column;
justify-content: center;
display: grid;
grid-template-rows: 100px 1fr;
grid-template-columns: 1fr;
align-items: center;
height: 100vh;
width: 100vw;
@@ -154,39 +180,53 @@ onUnmounted(() => {
font-size: 64px;
color: white;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
margin-bottom: 100px;
}
.middle-row {
main {
display: flex;
flex-direction: column;
gap: 100px;
margin-bottom: 100px;
}
.create-game-zone {
.create-game-zone,
header {
display: flex;
flex-direction: column;
align-items: center;
align-content: center;
justify-content: flex-start;
gap: 10px;
}
header {
flex-direction: row;
backdrop-filter: blur(50px);
height: 100%;
}
.create-game-zone {
flex-direction: column;
}
.create-game-zone button {
background-color: #4caf50;
}
button {
background-color: #4caf50;
border: none;
color: white;
text-align: center;
text-decoration: none;
display: inline-block;
font-family: "Roboto", sans-serif;
font-size: 16px;
margin: auto;
width: max-content;
cursor: pointer;
border-radius: 12px;
padding: 10px 24px;
height: 50px;
transition-duration: 0.4s;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
padding: 10px 24px;
height: 50px;
}
.games-list-zone {
@@ -197,21 +237,8 @@ onUnmounted(() => {
.games-list-zone button {
background-color: rgba(0, 0, 0, 0.8);
border: none;
color: white;
text-align: center;
text-decoration: none;
display: inline-block;
font-family: "Roboto", sans-serif;
font-size: 16px;
margin: auto;
cursor: pointer;
border-radius: 12px;
padding: 20px 24px;
height: 120px;
transition-duration: 0.4s;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}
.games-list-zone button.own_game {