Added creating new whiteboards from home screen, refactoring
This commit is contained in:
@@ -2,11 +2,11 @@
|
||||
|
||||
import { onMounted, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useWhiteboardStore } from '@/stores/whiteboards'
|
||||
import { useWhiteboardsStore } from '@/stores/whiteboards'
|
||||
import RecentWhiteboardsItem from './RecentWhiteboardsItem.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const store = useWhiteboardStore()
|
||||
const store = useWhiteboardsStore()
|
||||
|
||||
onMounted(() => {
|
||||
if (store.recentWhiteboards.length === 0) store.getRecentWhiteboards()
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useWhiteboardStore } from '@/stores/whiteboards'
|
||||
import { useWhiteboardsStore } from '@/stores/whiteboards'
|
||||
import WhiteboardHistoryItem from './WhiteboardHistoryItem.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const store = useWhiteboardStore()
|
||||
const store = useWhiteboardsStore()
|
||||
|
||||
onMounted(() => {
|
||||
if (store.ownedWhiteboards.length === 0) store.getWhiteboardHistory()
|
||||
|
||||
@@ -52,7 +52,10 @@ router.beforeEach((to) => {
|
||||
}
|
||||
|
||||
if (to.meta.requiresAuth && !auth.isAuthenticated) {
|
||||
return '/login'
|
||||
return {
|
||||
name: 'login',
|
||||
query: { redirect: to.fullPath }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// A small fetch-based HTTP client with automatic token attach and refresh-on-401.
|
||||
// This avoids circular imports by reading/writing tokens directly from localStorage.
|
||||
|
||||
const ACCESS_TOKEN = 'auth_token'
|
||||
const REFRESH_TOKEN = 'refresh_token'
|
||||
|
||||
@@ -9,7 +6,6 @@ async function parseJsonOrThrow(res: Response) {
|
||||
try {
|
||||
return text ? JSON.parse(text) : undefined
|
||||
} catch (e) {
|
||||
// non-JSON response
|
||||
return text
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,14 @@ export const whiteboardService = {
|
||||
async getRecentWhiteboards(): Promise<Whiteboard[]> {
|
||||
const raw = await api.get<any[]>('/api/Whiteboard/recent')
|
||||
return raw.map(mapWhiteboard)
|
||||
},
|
||||
|
||||
async createNewWhiteboard(title: string): Promise<string> {
|
||||
return await api.post<string>('/api/Whiteboard', { title: title, maxParticipants: 10, joinPolicy: 0})
|
||||
},
|
||||
|
||||
async getWhiteboardById(id: string): Promise<Whiteboard> {
|
||||
return await api.get<any>(`/api/Whiteboard/${id}`).then(mapWhiteboard)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ref, computed } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
import type { User, LoginCredentials, SignupCredentials, AuthResponse } from '@/types'
|
||||
import { useWhiteboardStore } from '@/stores/whiteboards'
|
||||
import { useWhiteboardsStore } from '@/stores/whiteboards'
|
||||
import { authService } from '@/services/authService'
|
||||
|
||||
const ACCESS_TOKEN = 'auth_token'
|
||||
@@ -129,7 +129,7 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
}
|
||||
|
||||
async function logout(allDevices = false) {
|
||||
const whiteboardStore = useWhiteboardStore()
|
||||
const whiteboardStore = useWhiteboardsStore()
|
||||
isLoading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ref } from 'vue'
|
||||
import type { Whiteboard } from '@/types'
|
||||
import { whiteboardService } from '@/services/whiteboardService'
|
||||
|
||||
export const useWhiteboardStore = defineStore('whiteboards', () => {
|
||||
export const useWhiteboardsStore = defineStore('whiteboards', () => {
|
||||
const ownedWhiteboards = ref<Whiteboard[]>([])
|
||||
const recentWhiteboards = ref<Whiteboard[]>([])
|
||||
const isLoading = ref(false)
|
||||
@@ -33,6 +33,25 @@ export const useWhiteboardStore = defineStore('whiteboards', () => {
|
||||
}
|
||||
}
|
||||
|
||||
async function createNewWhiteboard(title: string): Promise<string> {
|
||||
let newWhiteboard: Whiteboard;
|
||||
isLoading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const newId = await whiteboardService.createNewWhiteboard(title)
|
||||
newWhiteboard = await whiteboardService.getWhiteboardById(newId)
|
||||
} catch (err: any) {
|
||||
error.value = err.message ?? 'Failed to create whiteboard'
|
||||
throw err
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
ownedWhiteboards.value.push(newWhiteboard)
|
||||
return newWhiteboard.id;
|
||||
}
|
||||
|
||||
function clearWhiteboards() {
|
||||
ownedWhiteboards.value = []
|
||||
recentWhiteboards.value = []
|
||||
@@ -45,6 +64,7 @@ export const useWhiteboardStore = defineStore('whiteboards', () => {
|
||||
error,
|
||||
getWhiteboardHistory: getWhiteboardHistory,
|
||||
getRecentWhiteboards: getRecentWhiteboards,
|
||||
createNewWhiteboard: createNewWhiteboard,
|
||||
clearWhiteboards: clearWhiteboards
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,13 +1,38 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import { ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import WhiteboardHistorySidebar from '@/components/WhiteboardHistorySidebar.vue'
|
||||
import RecentWhiteboardsPanel from '@/components/RecentWhiteboardsPanel.vue'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useWhiteboardsStore } from "@/stores/whiteboards.ts";
|
||||
|
||||
const auth = useAuthStore()
|
||||
const whiteboards = useWhiteboardsStore()
|
||||
const router = useRouter()
|
||||
|
||||
const joinCode = ref('')
|
||||
const whiteboardTitle = ref('')
|
||||
const showCreateModal = ref(false)
|
||||
|
||||
async function handleCreateNewWhiteboard() {
|
||||
if (!whiteboardTitle.value.trim()) {
|
||||
alert('Please enter a title for the whiteboard.')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const newWhiteboardId = await whiteboards.createNewWhiteboard(whiteboardTitle.value.trim())
|
||||
|
||||
showCreateModal.value = false
|
||||
whiteboardTitle.value = ''
|
||||
|
||||
await router.push({ name: 'whiteboard', params: { id: newWhiteboardId } })
|
||||
} catch (e) {
|
||||
console.error('Failed to create new whiteboard', e)
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -80,7 +105,10 @@ const showCreateModal = ref(false)
|
||||
</div>
|
||||
<div class="modal-footer border-secondary">
|
||||
<button type="button" class="btn btn-secondary" @click="showCreateModal = false">Cancel</button>
|
||||
<button type="button" class="btn btn-primary">Create</button>
|
||||
<button type="button" class="btn btn-primary" @click="handleCreateNewWhiteboard">
|
||||
<span v-if="whiteboards.isLoading" class="spinner-border spinner-border-sm me-2"></span>
|
||||
Create
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -26,10 +26,13 @@ async function handleLeave() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="store.isLoading" class="d-flex justify-content-center align-items-center vh-100">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<div v-if="store.isLoading" class="d-flex flex-column justify-content-center align-items-center vh-100">
|
||||
<div class="spinner-border text-primary mb-3" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
<p class="text-muted fs-5 text-center">
|
||||
Please wait while your whiteboard is loading...
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-else-if="store.error" class="d-flex justify-content-center align-items-center vh-100">
|
||||
|
||||
@@ -22,7 +22,7 @@ export default defineConfig({
|
||||
target: 'http://localhost:5266',
|
||||
changeOrigin: true
|
||||
},
|
||||
'/hubs/': {
|
||||
'/hubs': {
|
||||
target: 'http://localhost:5039',
|
||||
changeOrigin: true,
|
||||
ws: true
|
||||
|
||||
Reference in New Issue
Block a user