Browse Source

*offline update fix

*can show profiles and invit from chat
master
Arnaud 2 years ago
committed by nicolas-arnaud
parent
commit
d376508a55
  1. 2
      back/volume/src/users/users.service.ts
  2. 2
      docker-compose.yml
  3. 61
      front/volume/src/App.svelte
  4. 37
      front/volume/src/components/Chat2.svelte
  5. 26
      front/volume/src/components/Friends.svelte
  6. 1
      front/volume/src/components/Leaderboard.svelte
  7. 122
      front/volume/src/components/Profile.svelte

2
back/volume/src/users/users.service.ts

@ -30,7 +30,7 @@ export class UsersService {
return user
}
@Cron('0 */60 * * *')
@Cron('0 * * * * *')
async updateStatus() {
let users = await this.usersRepository.find({})
users.forEach((usr) => {

2
docker-compose.yml

@ -31,7 +31,7 @@ services:
image: postgres
ports: [5432:5432]
volumes:
- /data/postgres:/data/postgres
- ./postgres:/var/lib/postgresql/data
networks: [transcendence]
restart: always
env_file: .env

61
front/volume/src/App.svelte

@ -4,8 +4,8 @@
import Profile from "./components/Profile.svelte";
import MatchHistory from "./components/MatchHistory.svelte";
import type { Match } from "./components/MatchHistory.svelte";
import Friends from "./components/Friends.svelte";
import type { Friend } from "./components/Friends.svelte";
import Friends,{addFriend} from "./components/Friends.svelte";
import type { Friend} from "./components/Friends.svelte";
import Spectate from "./components/Spectate.svelte";
import type { SpectateType } from "./components/Spectate.svelte";
import Pong from "./components/Pong/Pong.svelte";
@ -13,6 +13,7 @@
import Channels from "./components/Channels.svelte";
import type { ChannelsType } from "./components/Channels.svelte";
import Leaderboard from "./components/Leaderboard.svelte";
import type { Player } from "./components/Leaderboard.svelte"
import { store, getUser, login, logout, API_URL } from "./Auth";
@ -30,6 +31,21 @@
isProfileOpen = true;
}
let userProfile;
let isIdProfileOpen = false;
async function openIdProfile(event) {
console.log("Opening profile: " + event.detail)
isIdProfileOpen = true;
const res = await fetch(API_URL + "/user/" + event.detail, {
method: "get",
mode: "cors",
cache: "no-cache",
redirect: "follow",
referrerPolicy: "no-referrer",
});
userProfile = await res.json();
}
// HISTORY
let isHistoryOpen = false;
@ -112,10 +128,20 @@
selectedChannel = channel;
};
let leaderboard: Player[] = [];
export async function getLeader(): Promise<Player[]> {
let response = await fetch(API_URL + "/leader", {
credentials: "include",
mode: "cors",
});
return await response.json();
}
// LEADERBOARD
let isLeaderboardOpen = false;
function clickLeaderboard() {
async function clickLeaderboard() {
isLeaderboardOpen = true;
leaderboard = await getLeader();
}
</script>
@ -139,7 +165,8 @@
on:click={() => (selectedChannel = undefined)}
on:keydown={() => (selectedChannel = undefined)}
>
<Chat2 chatMessages={selectedChannel.messages} />
<Chat2 chatMessages={selectedChannel.messages}
on:view-profile={openIdProfile} on:add-friend={addFriend} />
</div>
{/if}
{#if !selectedChannel}
@ -164,7 +191,7 @@
on:click={() => (isLeaderboardOpen = false)}
on:keydown={() => (isLeaderboardOpen = false)}
>
<Leaderboard />
<Leaderboard {leaderboard}/>
</div>
{/if}
{#if isFriendOpen}
@ -173,7 +200,10 @@
isFriendOpen = false;
clearInterval(friendsInterval)
}}
on:keydown={() => (isFriendOpen = false)}
on:keydown={() => {
isFriendOpen = false;
clearInterval(friendsInterval)
}}
>
<Friends {friends} {invits} />
</div>
@ -192,12 +222,19 @@
on:keydown={() => (isProfileOpen = false)}
>
<Profile
username={$store.username}
wins={$store.wins}
losses={$store.looses}
winrate={$store.winrate}
rank={$store.rank}
is2faEnabled={false}
user = {$store}
edit = 1
/>
</div>
{/if}
{#if isIdProfileOpen}
<div
on:click={() => (isIdProfileOpen = false)}
on:keydown={() => (isIdProfileOpen = false)}
>
<Profile
user = {userProfile}
edit = 0
/>
</div>
{/if}

37
front/volume/src/components/Chat2.svelte

@ -1,10 +1,11 @@
<script lang="ts" context="module">
export interface chatMessagesType {
id: number;
name: string;
author: string;
text: string;
}
import { createEventDispatcher, onMount } from "svelte";
import { store } from "../Auth"
</script>
<script lang="ts">
@ -12,7 +13,7 @@
if (newText !== "") {
const newMessage = {
id: chatMessages.length + 1,
name: "You",
author: $store.username,
text: newText,
};
chatMessages = [...chatMessages.slice(-5 + 1), newMessage];
@ -30,14 +31,14 @@
const dispatch = createEventDispatcher();
let showProfileMenu = false;
let selectedUserId = null;
function openProfile(id : number) {
let selectedUser = null;
function openProfile(username : string) {
showProfileMenu = true;
selectedUserId = id;
selectedUser = username;
}
function closeProfileMenu() {
showProfileMenu = false;
selectedUserId = null;
selectedUser = "";
}
onMount(closeProfileMenu)
</script>
@ -49,11 +50,11 @@
<p class="message">
<span
class="message-name"
on:click={openProfile(message.id)}
on:keydown={openProfile(message.id)}
on:click={openProfile(message.author)}
on:keydown={openProfile(message.author)}
style="cursor: pointer;"
>
{message.name}
{message.author}
</span>: {message.text}
</p>
{/each}
@ -62,16 +63,16 @@
<div class="profile-menu" on:click|stopPropagation on:keydown|stopPropagation>
<ul>
<!-- if admin
<li><button on:click={() => dispatch('delete-user', selectedUserId)}>Delete User</button></li>
<li><button on:click={() => dispatch('ban-user', selectedUserId)}>Ban User</button></li>
<li><button on:click={() => dispatch('mute-user', selectedUserId)}>Mute User</button></li>
<li><button on:click={() => dispatch('promote-user', selectedUserId)}>Promote User</button></li>
<li><button on:click={() => dispatch('delete-user', selectedUser)}>Delete User</button></li>
<li><button on:click={() => dispatch('ban-user', selectedUser)}>Ban User</button></li>
<li><button on:click={() => dispatch('mute-user', selectedUser)}>Mute User</button></li>
<li><button on:click={() => dispatch('promote-user', selectedUser)}>Promote User</button></li>
-->
<li><button on:click={() => dispatch('send-message', selectedUserId)}>Send Message</button></li>
<li><button on:click={() => dispatch('view-profile', selectedUserId)}>View Profile</button></li>
<li><button on:click={() => dispatch('add-friend', selectedUserId)}>Add Friend</button></li>
<li><button on:click={() => dispatch('invite-to-game', selectedUserId)}>Invite to Game</button></li>
<li><button on:click={() => dispatch('block-user', selectedUserId)}>Block User</button></li>
<li><button on:click={() => dispatch('send-message', selectedUser)}>Send Message</button></li>
<li><button on:click={() => dispatch('view-profile', selectedUser)}>View Profile</button></li>
<li><button on:click={() => dispatch('add-friend', selectedUser)}>Add Friend</button></li>
<li><button on:click={() => dispatch('invite-to-game', selectedUser)}>Invite to Game</button></li>
<li><button on:click={() => dispatch('block-user', selectedUser)}>Block User</button></li>
<li><button on:click={closeProfileMenu}>Close</button></li>
</ul>
</div>

26
front/volume/src/components/Friends.svelte

@ -4,22 +4,13 @@
status: "online" | "offline" | "in a game";
ftId: number;
}
</script>
<script lang="ts">
import { API_URL } from "../Auth";
export let friends: Friend[];
export let invits: Friend[];
async function addFriend(event: any) {
export async function addFriend(event: any) {
console.log(typeof event);
event.preventDefault();
const usernameInput = event.target.querySelector('input[type="text"]');
console.log(usernameInput);
const username = usernameInput.value;
const username = event.target ?
event.target.querySelector('input[type="text"]').value
: event.detail;
let response = await fetch(API_URL + "/user/" + username, {
credentials: "include",
@ -36,11 +27,18 @@
} else {
console.log("Unknown user.");
}
usernameInput.value = "";
alert("Trying to add friend: " + username);
}
</script>
<script lang="ts">
import { API_URL } from "../Auth";
export let friends: Friend[];
export let invits: Friend[];
</script>
<div class="overlay">
<div class="friends" on:click|stopPropagation on:keydown|stopPropagation>
<div>

1
front/volume/src/components/Leaderboard.svelte

@ -3,6 +3,7 @@
username: string;
wins: number;
losses: number;
winrate: number;
rank: number;
}
</script>

122
front/volume/src/components/Profile.svelte

@ -1,13 +1,15 @@
<script lang="ts">
import { API_URL, store, logout } from "../Auth";
export let username = "";
export let wins = 0;
export let losses = 0;
export let winrate = 0;
export let elo = 0;
export let rank = -1;
export let is2faEnabled = false;
export let edit = false
export let user = {
username: "",
wins: 0,
losses: 0,
winrate: 0,
rank: -1,
is2faEnabled: false
}
async function handleSubmit() {
let response = await fetch(API_URL, {
@ -24,8 +26,9 @@
async function handle2fa(event: Event) {
event.preventDefault();
alert("Trying to " + (is2faEnabled ? "disable" : "enable") + " 2FA");
alert("Trying to " + (user.is2faEnabled ? "disable" : "enable") + " 2FA");
}
function submitAvatar() {
let form: HTMLFormElement = <HTMLFormElement>(
document.getElementById("upload_avatar")
@ -36,49 +39,44 @@
<div class="overlay">
<div class="profile" on:click|stopPropagation on:keydown|stopPropagation>
<h3>===| <mark>{user.username}'s Profile</mark> |===</h3>
<div class="profile-header">
<form
action={API_URL + "/avatar"}
method="post"
enctype="multipart/form-data"
id="upload_avatar"
>
<div class="input-avatar">
<label for="avatar-input">
<img src={API_URL + "/avatar"} alt="avatar" class="profile-img" />
</label>
<input
type="file"
id="avatar-input"
name="avatar"
on:change={submitAvatar}
/>
</div>
</form>
{#if edit == 0}
<img src={API_URL + "/avatar"} alt="avatar" class="profile-img" />
{:else}
<form
action={API_URL + "/avatar"}
method="post"
enctype="multipart/form-data"
id="upload_avatar"
>
<input type="file" id="avatar-input" name="avatar" on:change={submitAvatar} />
</form>
<label class="img-class" for="avatar-input">
<img src={API_URL + "/avatar"} alt="avatar"/>
</label>
{/if}
</div>
<div class="profile-body">
<form on:submit|preventDefault={handleSubmit}>
<div class="username">
<label for="username">Username</label>
<input type="text" id="username" bind:value={username} />
<button type="submit">Submit</button>
</div>
</form>
<p>Wins: {wins}</p>
<p>Losses: {losses}</p>
<p>Winrate: {winrate}%</p>
<p>Elo : {elo}</p>
<p>Rank: {rank}</p>
<form class="two-factor-auth" on:submit={handle2fa}>
<button type="submit">
{#if is2faEnabled}
Disable 2FA
{:else}
Enable 2FA
{/if}
</button>
</form>
<button type="button" on:click={logout}>Log Out</button>
<p>Wins: {user.wins}</p>
<p>Losses: {user.losses}</p>
<p>Winrate: {user.winrate}%</p>
<p>Rank: {user.rank}</p>
{#if edit == 1}
<form id="username-form" class="username" on:submit|preventDefault={handleSubmit}>
<input type="text" id="username" bind:value={user.username} />
<button type="submit" class="username" form="username-form">Change</button>
</form>
<button type="button" on:click={handle2fa}>
{#if user.is2faEnabled}
Disable 2FA
{:else}
Enable user.2FA
{/if}
</button>
<button id="logout" type="button" on:click={logout}>Log Out</button>
{/if}
</div>
</div>
</div>
@ -110,17 +108,39 @@
align-items: center;
}
.profile-img {
.profile-header {
width: 80px;
height: 80px;
margin-right: 1rem;
margin:auto;
justify-content: center;
}
.two-factor-auth {
margin-top: 1rem;
}
.input-avatar > input {
#avatar-input {
display: none;
}
.profile > h3 {
display: flex;
justify-content: center;
}
.profile-body > p {
display: flex;
justify-content: center;
}
.profile-body > img {
display: flex;
justify-content: center;
}
.username {
text-align: center;
}
#logout {
float: right;
}
</style>

Loading…
Cancel
Save