added roominvites in frontend in a notifications page and added clap to define backend port
This commit is contained in:
@@ -13,7 +13,7 @@
|
|||||||
"identifier": "http:default",
|
"identifier": "http:default",
|
||||||
"allow": [
|
"allow": [
|
||||||
{
|
{
|
||||||
"url": "http://192.168.1.147:*"
|
"url": "http://127.0.0.1:*"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "https://alatreon.org/chatapp/*"
|
"url": "https://alatreon.org/chatapp/*"
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
"identifier": "websocket:default",
|
"identifier": "websocket:default",
|
||||||
"allow": [
|
"allow": [
|
||||||
{
|
{
|
||||||
"url": "ws://192.168.1.147:*"
|
"url": "ws://127.0.0.1:*"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "wss://alatreon.org/chatapp/*"
|
"url": "wss://alatreon.org/chatapp/*"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { fetch } from '@tauri-apps/plugin-http';
|
import { fetch } from '@tauri-apps/plugin-http';
|
||||||
import { initAuth, logout } from '../store.ts'
|
import { getAuthData, clearAuthData } from '../authStore'
|
||||||
import { API } from '../main.ts'
|
import { API } from '../main.ts'
|
||||||
import router from '../router'
|
import router from '../router'
|
||||||
|
|
||||||
@@ -7,12 +7,11 @@ export async function apiFetch<T>(
|
|||||||
path: string,
|
path: string,
|
||||||
options: RequestInit = {}
|
options: RequestInit = {}
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
const auth = await initAuth()
|
const auth = await getAuthData()
|
||||||
|
|
||||||
const res = await fetch(`${API}${path}`, {
|
const res = await fetch(`${API}${path}`, {
|
||||||
method: options.method || 'GET',
|
|
||||||
body: options.body,
|
|
||||||
...options,
|
...options,
|
||||||
|
method: options.method || 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
...(auth.token ? { Authorization: `Bearer ${auth.token}` } : {}),
|
...(auth.token ? { Authorization: `Bearer ${auth.token}` } : {}),
|
||||||
@@ -21,7 +20,7 @@ export async function apiFetch<T>(
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (res.status === 401) {
|
if (res.status === 401) {
|
||||||
await logout()
|
await clearAuthData()
|
||||||
router.push('/login')
|
router.push('/login')
|
||||||
throw new Error("Session expired")
|
throw new Error("Session expired")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { apiFetch } from './client'
|
import { apiFetch } from './client'
|
||||||
import type { Room } from '../types'
|
import type { Room, RoomInvite } from '../types'
|
||||||
|
|
||||||
export function fetchRooms(userUuid: string) {
|
export function fetchRooms() {
|
||||||
return apiFetch<Room[]>(`/rooms/${userUuid}`)
|
return apiFetch<Room[]>(`/rooms`)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createRoom(name: string, global: boolean) {
|
export function createRoom(name: string, global: boolean) {
|
||||||
@@ -12,3 +12,20 @@ export function createRoom(name: string, global: boolean) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function fetchRoomInvites() {
|
||||||
|
return apiFetch<RoomInvite[]>('/rooms/invites')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sendRoomInvite(receiverUsername: string, roomUuid: string) {
|
||||||
|
return apiFetch<void>('/rooms/invite', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({ receiver_username: receiverUsername, room_uuid: roomUuid }),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function acceptRoomInvite(senderUuid: string, roomUuid: string) {
|
||||||
|
return apiFetch<void>('/rooms/join', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({ sender_uuid: senderUuid, room_uuid: roomUuid }),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
41
src/authStore.ts
Normal file
41
src/authStore.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { load, Store } from '@tauri-apps/plugin-store'
|
||||||
|
|
||||||
|
let store: Store | null = null
|
||||||
|
|
||||||
|
async function getStore() {
|
||||||
|
if (!store) store = await load('store.json')
|
||||||
|
return store
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getAuthData() {
|
||||||
|
const s = await getStore()
|
||||||
|
const token = await s.get<string>('token')
|
||||||
|
const uuid = await s.get<string>('uuid')
|
||||||
|
return { token: token || null, uuid: uuid || null, isAuthenticated: !!token }
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveAuthData(token: string, uuid: string) {
|
||||||
|
const s = await getStore()
|
||||||
|
await s.set('token', token)
|
||||||
|
await s.set('uuid', uuid)
|
||||||
|
await s.save()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function clearAuthData() {
|
||||||
|
const s = await getStore()
|
||||||
|
await s.delete('token')
|
||||||
|
await s.delete('uuid')
|
||||||
|
await s.save()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setLastRoom(uuid: string) {
|
||||||
|
if (!uuid || uuid === 'none') return
|
||||||
|
const s = await getStore()
|
||||||
|
await s.set('last_room_uuid', uuid)
|
||||||
|
await s.save()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getLastRoom(): Promise<string | null> {
|
||||||
|
const s = await getStore()
|
||||||
|
return (await s.get<string>('last_room_uuid')) ?? null
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, nextTick, defineExpose } from 'vue'
|
import { ref, nextTick } from 'vue'
|
||||||
|
|
||||||
const content = ref('')
|
const content = ref('')
|
||||||
const textareaRef = ref<HTMLTextAreaElement | null>(null)
|
const textareaRef = ref<HTMLTextAreaElement | null>(null)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<nav id="bottom-nav">
|
<nav id="bottom-nav">
|
||||||
<router-link to="/rooms/none" class="nav-item" :class="{ 'router-link-active': $route.name === 'chat' }">
|
<router-link to="/" class="nav-item" :class="{ 'router-link-active': $route.name === 'chat' }">
|
||||||
<i class="fa-solid fa-message"></i>
|
<i class="fa-solid fa-message"></i>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
@@ -9,6 +9,10 @@
|
|||||||
<i class="fa-solid fa-user-group"></i>
|
<i class="fa-solid fa-user-group"></i>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
|
<router-link to="/notifications" class="nav-item">
|
||||||
|
<i class="fa-solid fa-bell"></i>
|
||||||
|
</router-link>
|
||||||
|
|
||||||
<button class="nav-item logout" @click="logout">
|
<button class="nav-item logout" @click="logout">
|
||||||
<i class="fa-solid fa-right-from-bracket"></i>
|
<i class="fa-solid fa-right-from-bracket"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -15,5 +15,5 @@ async function init() {
|
|||||||
|
|
||||||
init()
|
init()
|
||||||
|
|
||||||
export const API = 'http://192.168.1.147:8081'
|
export const API = 'http://127.0.0.1:8080'
|
||||||
export const API_WS = 'ws://192.168.1.147:8081/ws'
|
export const API_WS = 'ws://127.0.0.1:8080/ws'
|
||||||
|
|||||||
@@ -14,57 +14,31 @@
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="friends-requests-container">
|
<!-- Friends List -->
|
||||||
<!-- Friends List -->
|
<div class="friends-list">
|
||||||
<div class="friends-list">
|
<h2>Your Friends</h2>
|
||||||
<h2>Your Friends</h2>
|
<ul>
|
||||||
<ul>
|
<li v-for="friend in friends" :key="friend.uuid">
|
||||||
<li v-for="friend in friends" :key="friend.uuid">
|
{{ friend.username }}
|
||||||
{{ friend.username }}
|
</li>
|
||||||
</li>
|
</ul>
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Friend Request List -->
|
|
||||||
<div class="requests">
|
|
||||||
<h2>Friend Requests</h2>
|
|
||||||
<ul v-if="requests.length">
|
|
||||||
<li v-for="req in requests" :key="req.sender_uuid">
|
|
||||||
<span>{{ req.sender_username }}</span>
|
|
||||||
<button @click="accept(req.sender_uuid)">Accept</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<p v-else>No pending requests</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, ref } from 'vue'
|
import { onMounted, ref } from 'vue'
|
||||||
import { fetchFriends, fetchFriendRequests, acceptFriendRequest, sendFriendRequest } from '../api/friends'
|
import { fetchFriends, sendFriendRequest } from '../api/friends'
|
||||||
import type { Friend, FriendRequest } from '../types'
|
import type { Friend } from '../types'
|
||||||
|
|
||||||
const friends = ref<Friend[]>([])
|
const friends = ref<Friend[]>([])
|
||||||
const requests = ref<FriendRequest[]>([])
|
|
||||||
const username = ref('')
|
const username = ref('')
|
||||||
const errorMessage = ref('')
|
const errorMessage = ref('')
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
friends.value = await fetchFriends()
|
friends.value = await fetchFriends()
|
||||||
requests.value = await fetchFriendRequests()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
async function accept(senderUuid: string) {
|
|
||||||
try {
|
|
||||||
await acceptFriendRequest(senderUuid)
|
|
||||||
requests.value = requests.value.filter(r => r.sender_uuid !== senderUuid)
|
|
||||||
fetchFriends().then(f => (friends.value = f))
|
|
||||||
} catch (err) {
|
|
||||||
errorMessage.value = 'An error occurred while accepting the request.' // TODO: handle this supposedly impossible case
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function send() {
|
async function send() {
|
||||||
if (!username.value) {
|
if (!username.value) {
|
||||||
// errorMessage.value = 'Username is required.'
|
// errorMessage.value = 'Username is required.'
|
||||||
@@ -125,14 +99,7 @@ async function send() {
|
|||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.friends-requests-container {
|
.friends-list {
|
||||||
display: flex;
|
|
||||||
gap: 2rem;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.friends-list,
|
|
||||||
.requests {
|
|
||||||
min-width: 250px;
|
min-width: 250px;
|
||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
@@ -140,14 +107,12 @@ async function send() {
|
|||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.friends-list ul,
|
.friends-list ul {
|
||||||
.requests ul {
|
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.friends-list li,
|
.friends-list li {
|
||||||
.requests li {
|
|
||||||
background: var(--panel-light);
|
background: var(--panel-light);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
@@ -155,41 +120,8 @@ async function send() {
|
|||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.requests {
|
.friends-list h2 {
|
||||||
max-height: 500px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.requests li {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
background: var(--panel-light);
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
border-radius: var(--radius);
|
|
||||||
padding: 0.75rem 1rem;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.requests li button {
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.requests p {
|
|
||||||
font-size: 0.9rem;
|
|
||||||
color: gray;
|
|
||||||
}
|
|
||||||
|
|
||||||
.friends-list h2,
|
|
||||||
.requests h2 {
|
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 720px) {
|
|
||||||
.friends-requests-container {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
149
src/pages/NotificationsPage.vue
Normal file
149
src/pages/NotificationsPage.vue
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
<template>
|
||||||
|
<div class="notifications-page">
|
||||||
|
<h1>Notifications</h1>
|
||||||
|
|
||||||
|
<p v-if="errorMessage" class="error-message">{{ errorMessage }}</p>
|
||||||
|
|
||||||
|
<!-- Friend Request List -->
|
||||||
|
<div class="list">
|
||||||
|
<h2>Friend Requests</h2>
|
||||||
|
<ul v-if="requests.length">
|
||||||
|
<li v-for="req in requests" :key="req.sender_uuid">
|
||||||
|
<span>{{ req.sender_username }}</span>
|
||||||
|
<button @click="acceptFriend(req.sender_uuid)">Accept</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p v-else>No pending requests</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Room Invites List -->
|
||||||
|
<div class="list">
|
||||||
|
<h2>Room Invites</h2>
|
||||||
|
<ul v-if="invites.length">
|
||||||
|
<li v-for="inv in invites" :key="inv.sender_uuid">
|
||||||
|
<span>{{ inv.room_name }}</span>
|
||||||
|
<span>from: {{ inv.sender_username }}</span>
|
||||||
|
<button @click="acceptRoom(inv.sender_uuid, inv.room_uuid)">Join</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p v-else>No pending invites</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, ref } from 'vue'
|
||||||
|
import { fetchFriendRequests, acceptFriendRequest } from '../api/friends'
|
||||||
|
import { fetchRoomInvites, acceptRoomInvite } from '../api/rooms.ts'
|
||||||
|
import type { FriendRequest, RoomInvite } from '../types'
|
||||||
|
|
||||||
|
const requests = ref<FriendRequest[]>([])
|
||||||
|
const invites = ref<RoomInvite[]>([])
|
||||||
|
const errorMessage = ref('')
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
requests.value = await fetchFriendRequests()
|
||||||
|
invites.value = await fetchRoomInvites()
|
||||||
|
})
|
||||||
|
|
||||||
|
async function acceptFriend(senderUuid: string) {
|
||||||
|
try {
|
||||||
|
await acceptFriendRequest(senderUuid)
|
||||||
|
requests.value = requests.value.filter(r => r.sender_uuid !== senderUuid)
|
||||||
|
// fetchFriends().then(f => (friends.value = f))
|
||||||
|
} catch (err) {
|
||||||
|
errorMessage.value = 'An error occurred while accepting the request.' // TODO: handle this case
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function acceptRoom(senderUuid: string, roomUuid: string) {
|
||||||
|
try {
|
||||||
|
await acceptRoomInvite(senderUuid, roomUuid)
|
||||||
|
invites.value = invites.value.filter(r => r.room_uuid !== roomUuid)
|
||||||
|
// fetchFriends().then(f => (friends.value = f))
|
||||||
|
} catch (err) {
|
||||||
|
errorMessage.value = 'An error occurred while accepting the invite.' // TODO: handle this case
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.notifications-page {
|
||||||
|
max-width: 720px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem 1.5rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
color: red;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.friend-requests-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 2rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list {
|
||||||
|
min-width: 250px;
|
||||||
|
background: var(--panel);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list li {
|
||||||
|
background: var(--panel-light);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list {
|
||||||
|
max-height: 500px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list li {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
background: var(--panel-light);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list li button {
|
||||||
|
padding-top: 5px;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list p {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list h2 {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.friend-requests-container {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -4,6 +4,7 @@ import { initAuth, getLastRoom, setLastRoom } from './store'
|
|||||||
import LoginPage from './pages/LoginPage.vue'
|
import LoginPage from './pages/LoginPage.vue'
|
||||||
import ChatPage from './pages/ChatPage.vue'
|
import ChatPage from './pages/ChatPage.vue'
|
||||||
import FriendListPage from './pages/FriendListPage.vue'
|
import FriendListPage from './pages/FriendListPage.vue'
|
||||||
|
import NofificationsPage from './pages/NotificationsPage.vue'
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(),
|
history: createWebHistory(),
|
||||||
@@ -21,7 +22,8 @@ const router = createRouter({
|
|||||||
component: ChatPage,
|
component: ChatPage,
|
||||||
props: true
|
props: true
|
||||||
},
|
},
|
||||||
{ path: '/friendlist', component: FriendListPage }
|
{ path: '/friendlist', component: FriendListPage },
|
||||||
|
{ path: '/notifications', component: NofificationsPage }
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
58
src/store.ts
58
src/store.ts
@@ -1,36 +1,10 @@
|
|||||||
import { load, Store } from '@tauri-apps/plugin-store'
|
|
||||||
import type { LoginResponse } from './types'
|
|
||||||
import { apiFetch } from './api/client'
|
import { apiFetch } from './api/client'
|
||||||
|
import type { LoginResponse } from './types'
|
||||||
|
import * as authStore from './authStore'
|
||||||
|
|
||||||
let store: Store | null = null
|
export const initAuth = authStore.getAuthData
|
||||||
|
export const getLastRoom = authStore.getLastRoom
|
||||||
async function getStore() {
|
export const setLastRoom = authStore.setLastRoom
|
||||||
if (!store) {
|
|
||||||
store = await load('store.json')
|
|
||||||
}
|
|
||||||
return store
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function setLastRoom(uuid: string) {
|
|
||||||
if (!uuid || uuid === 'none') return
|
|
||||||
|
|
||||||
const s = await getStore()
|
|
||||||
await s.set('last_room_uuid', uuid)
|
|
||||||
await s.save()
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getLastRoom(): Promise<string | null> {
|
|
||||||
const s = await getStore()
|
|
||||||
const lastRoom = await s.get<string>('last_room_uuid')
|
|
||||||
return lastRoom ?? null
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function initAuth() {
|
|
||||||
const s = await getStore()
|
|
||||||
const token = await s.get<string>('token')
|
|
||||||
const uuid = await s.get<string>('uuid')
|
|
||||||
return { token: token || null, uuid: uuid || null, isAuthenticated: !!token }
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function login(email: string, username: string, password: string) {
|
export async function login(email: string, username: string, password: string) {
|
||||||
const res: LoginResponse = await apiFetch('/login', {
|
const res: LoginResponse = await apiFetch('/login', {
|
||||||
@@ -38,35 +12,23 @@ export async function login(email: string, username: string, password: string) {
|
|||||||
body: JSON.stringify({ email, username, password }),
|
body: JSON.stringify({ email, username, password }),
|
||||||
})
|
})
|
||||||
|
|
||||||
const s = await getStore()
|
await authStore.saveAuthData(res.token, res.uuid)
|
||||||
await s.set('token', res.token)
|
|
||||||
await s.set('uuid', res.uuid)
|
|
||||||
await s.save()
|
|
||||||
|
|
||||||
return { token: res.token, uuid: res.uuid, isAuthenticated: true }
|
return { token: res.token, uuid: res.uuid, isAuthenticated: true }
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function logout() {
|
export async function logout() {
|
||||||
const s = await getStore()
|
await authStore.clearAuthData()
|
||||||
await s.delete('token')
|
|
||||||
await s.delete('uuid')
|
|
||||||
await s.save()
|
|
||||||
return { token: null, uuid: null, isAuthenticated: false }
|
return { token: null, uuid: null, isAuthenticated: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function validateToken(): Promise<boolean> {
|
export async function validateToken(): Promise<boolean> {
|
||||||
const auth = await initAuth()
|
const auth = await authStore.getAuthData()
|
||||||
if (!auth.token) return false
|
if (!auth.token) return false
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await apiFetch('/validate-token')
|
await apiFetch('/validate-token')
|
||||||
return true
|
return true
|
||||||
} catch (e: any) {
|
} catch (e) {
|
||||||
// Only logout if token is bad
|
return false
|
||||||
if (e.message.includes('401')) {
|
|
||||||
await logout()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,3 +27,10 @@ export interface FriendRequest {
|
|||||||
sender_uuid: string
|
sender_uuid: string
|
||||||
sender_username: string
|
sender_username: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RoomInvite {
|
||||||
|
room_uuid: string
|
||||||
|
room_name: string
|
||||||
|
sender_uuid: string
|
||||||
|
sender_username: string
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user