diff --git a/fe/src/components/CreateListModal.vue b/fe/src/components/CreateListModal.vue new file mode 100644 index 0000000..834321d --- /dev/null +++ b/fe/src/components/CreateListModal.vue @@ -0,0 +1,102 @@ + + + diff --git a/fe/src/pages/GroupDetailPage.vue b/fe/src/pages/GroupDetailPage.vue index c7b2ade..5c61eac 100644 --- a/fe/src/pages/GroupDetailPage.vue +++ b/fe/src/pages/GroupDetailPage.vue @@ -67,16 +67,10 @@ const fetchGroupDetails = async () => { if (!groupId.value) return; loading.value = true; try { - // console.log( - // `TODO: Implement API call to fetch group details for group ID: ${groupId.value} from /api/v1/groups/{group_id}`, - // ); const response = await api.get(`/api/v1/groups/${groupId.value}`, { headers: { Authorization: `Bearer ${authStore.token}` }, }); group.value = response.data; - - // Mock data for now - // group.value = { id: groupId.value, name: `Sample Group ${groupId.value}` }; } catch (error: any) { console.error('Error fetching group details:', error); $q.notify({ @@ -84,7 +78,6 @@ const fetchGroupDetails = async () => { message: error.response?.data?.detail || 'Failed to fetch group details.', icon: 'report_problem', }); - // Handle error (e.g., show notification, redirect) } finally { loading.value = false; } @@ -93,9 +86,8 @@ const fetchGroupDetails = async () => { const generateInviteCode = async () => { if (!groupId.value) return; generatingInvite.value = true; - inviteCode.value = null; // Reset previous code + inviteCode.value = null; try { - // console.log(`TODO: Implement API call to POST /api/v1/groups/${groupId.value}/invites`); const response = await api.post( `/api/v1/groups/${groupId.value}/invites`, {}, @@ -103,10 +95,7 @@ const generateInviteCode = async () => { headers: { Authorization: `Bearer ${authStore.token}` }, }, ); - inviteCode.value = response.data.invite_code; // Assuming API returns { invite_code: 'XXXXX' } - - // Mock data for now - // inviteCode.value = `INVITE_${groupId.value}_${Math.random().toString(36).substring(2, 7).toUpperCase()}`; + inviteCode.value = response.data.invite_code; $q.notify({ color: 'positive', message: 'Invite code generated successfully!', @@ -119,7 +108,6 @@ const generateInviteCode = async () => { message: error.response?.data?.detail || 'Failed to generate invite code.', icon: 'report_problem', }); - // Handle error } finally { generatingInvite.value = false; } @@ -130,11 +118,10 @@ const copyInviteCode = () => { copyToClipboard(inviteCode.value) .then(() => { copySuccess.value = true; - setTimeout(() => (copySuccess.value = false), 2000); // Hide message after 2s + setTimeout(() => (copySuccess.value = false), 2000); }) .catch(() => { console.error('Failed to copy invite code'); - // Handle copy error (e.g., show a notification) }); } }; diff --git a/fe/src/pages/GroupsPage.vue b/fe/src/pages/GroupsPage.vue index 01935e1..74b7d82 100644 --- a/fe/src/pages/GroupsPage.vue +++ b/fe/src/pages/GroupsPage.vue @@ -89,7 +89,7 @@ import { ref, onMounted } from 'vue'; import { useRouter } from 'vue-router'; import { QInput, useQuasar } from 'quasar'; // Import QInput for type reference import { api } from 'boot/axios'; // Assuming you have an axios instance set up -import { useAuthStore } from 'stores/auth'; // If needed for auth token +import { useAuthStore } from 'stores/auth'; interface Group { id: string; // or number, depending on your API @@ -98,7 +98,7 @@ interface Group { } const router = useRouter(); -const authStore = useAuthStore(); // If needed +const authStore = useAuthStore(); const $q = useQuasar(); const groups = ref([]); @@ -106,27 +106,19 @@ const loading = ref(false); const showCreateGroupModal = ref(false); const newGroupName = ref(''); const creatingGroup = ref(false); -const newGroupNameInput = ref(null); // For focusing and validation +const newGroupNameInput = ref(null); -// For Join Group const inviteCodeToJoin = ref(''); const joiningGroup = ref(false); const joinInviteCodeInput = ref(null); -// Fetch groups from API const fetchGroups = async () => { loading.value = true; try { const response = await api.get('/api/v1/groups', { - headers: { Authorization: `Bearer ${authStore.token}` }, // If auth is needed + headers: { Authorization: `Bearer ${authStore.token}` }, }); groups.value = response.data; - // console.log('TODO: Implement API call to fetch groups /api/v1/groups'); - // Mock data for now: - // groups.value = [ - // { id: '1', name: 'First Group' }, - // { id: '2', name: 'Second Group' }, - // ]; } catch (error: any) { console.error('Error fetching groups:', error); $q.notify({ @@ -149,12 +141,9 @@ const handleCreateGroup = async () => { const response = await api.post( '/api/v1/groups', { name: newGroupName.value }, - { headers: { Authorization: `Bearer ${authStore.token}` } }, // If auth is needed + { headers: { Authorization: `Bearer ${authStore.token}` } }, ); groups.value.push(response.data); // Add new group to the list - // console.log('TODO: Implement API call to POST /api/v1/groups with name:', newGroupName.value); - // Mock adding group - // groups.value.push({ id: String(Date.now()), name: newGroupName.value }); showCreateGroupModal.value = false; newGroupName.value = ''; $q.notify({ @@ -181,16 +170,11 @@ const handleJoinGroup = async () => { } joiningGroup.value = true; try { - // console.log( - // 'TODO: Implement API call to POST /api/v1/invites/accept with code:', - // inviteCodeToJoin.value, - // ); const response = await api.post( '/api/v1/invites/accept', - { invite_code: inviteCodeToJoin.value }, // Ensure schema matches backend (invite_code vs code) - { headers: { Authorization: `Bearer ${authStore.token}` } }, // If auth is needed + { invite_code: inviteCodeToJoin.value }, + { headers: { Authorization: `Bearer ${authStore.token}` } }, ); - // On success, refresh the list of groups and clear input await fetchGroups(); inviteCodeToJoin.value = ''; $q.notify({ @@ -198,9 +182,6 @@ const handleJoinGroup = async () => { message: response.data.detail || 'Successfully joined group!', icon: 'check_circle', }); - // console.log('Successfully joined group (mock). Refreshing groups...'); - // await fetchGroups(); // Refresh groups after mock join - // inviteCodeToJoin.value = ''; } catch (error: any) { console.error('Error joining group:', error); $q.notify({ @@ -215,9 +196,7 @@ const handleJoinGroup = async () => { const selectGroup = (group: Group) => { console.log('Selected group:', group); - // For MVP, just displaying the group name and having it as context for lists is enough. - router.push(`/groups/${group.id}`); // Navigate to group detail page - // console.log('TODO: Implement navigation to group detail page /groups/:id or handle selection'); + router.push(`/groups/${group.id}`); }; onMounted(() => { diff --git a/fe/src/pages/ListDetailPage.vue b/fe/src/pages/ListDetailPage.vue new file mode 100644 index 0000000..e190475 --- /dev/null +++ b/fe/src/pages/ListDetailPage.vue @@ -0,0 +1,399 @@ + + + + + diff --git a/fe/src/pages/ListsPage.vue b/fe/src/pages/ListsPage.vue index 722ba1e..ae8f3fb 100644 --- a/fe/src/pages/ListsPage.vue +++ b/fe/src/pages/ListsPage.vue @@ -1,10 +1,156 @@ + + diff --git a/fe/src/router/routes.ts b/fe/src/router/routes.ts index c867718..ccf2f30 100644 --- a/fe/src/router/routes.ts +++ b/fe/src/router/routes.ts @@ -6,10 +6,27 @@ const routes: RouteRecordRaw[] = [ component: () => import('layouts/MainLayout.vue'), children: [ { path: '', redirect: '/lists' }, - { path: 'lists', component: () => import('pages/ListsPage.vue') }, - { path: 'groups', component: () => import('pages/GroupsPage.vue') }, - { path: 'groups/:id', component: () => import('pages/GroupDetailPage.vue'), props: true }, - { path: 'account', component: () => import('pages/AccountPage.vue') }, + { path: 'lists', name: 'PersonalLists', component: () => import('pages/ListsPage.vue') }, + { + path: 'lists/:id', + name: 'ListDetail', + component: () => import('pages/ListDetailPage.vue'), + props: true, + }, + { path: 'groups', name: 'GroupsList', component: () => import('pages/GroupsPage.vue') }, + { + path: 'groups/:id', + name: 'GroupDetail', + component: () => import('pages/GroupDetailPage.vue'), + props: true, + }, + { + path: 'groups/:groupId/lists', + name: 'GroupLists', + component: () => import('pages/ListsPage.vue'), + props: true, + }, + { path: 'account', name: 'Account', component: () => import('pages/AccountPage.vue') }, ], },