Skip to content

Commit dc9dc27

Browse files
committed
created Homeview
1 parent ae96421 commit dc9dc27

4 files changed

Lines changed: 112 additions & 60 deletions

File tree

frontend/src/components/templates/MainLayout.vue

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,18 @@ const projectLinks = computed<Project[]>(() =>
5252
})),
5353
)
5454
55-
const showNewQuery = computed(() => route.name !== 'search')
55+
const showNewQuery = computed(() => route.name !== 'search' && route.name !== 'home')
5656
5757
// ----- handlers -----
5858
5959
const toggleSidebar = () => {
6060
sidebarOpen.value = !sidebarOpen.value
6161
}
6262
63-
const goToSearch = () => router.push({ name: 'search' })
63+
const goToHome = () => router.push({ name: 'home' })
6464
6565
const handleNewQuery = () => {
66-
goToSearch()
66+
goToHome()
6767
sidebarOpen.value = false
6868
}
6969
@@ -88,7 +88,7 @@ const handleDeleteProject = async (projectId: number) => {
8888
await projectsStore.deleteExistingProject(projectId)
8989
9090
if (route.name === 'project' && Number(route.params.projectId) === projectId) {
91-
await goToSearch()
91+
await goToHome()
9292
sidebarOpen.value = true
9393
}
9494
}

frontend/src/pages/HomePage.vue

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<script setup lang="ts">
2+
import { useRouter } from 'vue-router';
3+
import SearchInputSection from '@/components/organisms/search/SearchInputSection.vue';
4+
5+
const router = useRouter();
6+
7+
const handleSearch = (payload: { query: string; file: File | null } | string) => {
8+
const query = typeof payload === 'string' ? payload : payload.query;
9+
const file = typeof payload !== 'string' && payload.file ? payload.file : null;
10+
11+
// Navigate to the search route.
12+
// We pass strings via query params, and Files via history state
13+
router.push({
14+
name: 'search',
15+
query: { q: query },
16+
state: { file: file } // Pass the file object invisibly via History API
17+
});
18+
};
19+
</script>
20+
21+
<template>
22+
<div class="home-page">
23+
<SearchInputSection @submit="handleSearch" />
24+
</div>
25+
</template>
26+
27+
<style scoped>
28+
.home-page {
29+
max-width: 1200px;
30+
margin: 0 auto;
31+
padding: 8px;
32+
/* Center vertically like the original start screen often does */
33+
min-height: 60vh;
34+
display: flex;
35+
align-items: center;
36+
justify-content: center;
37+
}
38+
</style>

frontend/src/pages/SearchPage.vue

Lines changed: 62 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
2-
import { computed, onMounted, ref } from 'vue';
2+
import { computed, onMounted, ref, watch } from 'vue';
3+
import { useRoute, useRouter } from 'vue-router';
34
import {
45
VAlert,
56
VBtn,
@@ -13,9 +14,7 @@ import {
1314
VSpacer,
1415
} from 'vuetify/components';
1516
16-
import SearchInputSection from '@/components/organisms/search/SearchInputSection.vue';
1717
import SearchResultsSection from '@/components/organisms/search/SearchResultsSection.vue';
18-
1918
import PdfViewerDialog from '@/components/organisms/pdf/PdfViewerDialog.vue';
2019
import type { Paper } from '@/types/content';
2120
@@ -24,67 +23,75 @@ import { useAuthStore } from '@/stores/auth';
2423
import { useProjectsStore } from '@/stores/projects';
2524
import { mapSearchResponseToPapers } from '@/mappers/paper-mapper';
2625
26+
const route = useRoute();
27+
const router = useRouter();
2728
const authStore = useAuthStore();
2829
const projectsStore = useProjectsStore();
2930
30-
// State to track the active search context
31-
const hasActiveSearch = ref(false);
31+
// ----- state -----
3232
const currentQueryText = ref('');
3333
const currentFile = ref<File | null>(null);
3434
3535
const outputs = ref<Paper[]>([]);
3636
const isLoading = ref(false);
3737
const errorMessage = ref<string | null>(null);
3838
39-
// add-to-project dialog state
39+
// Dialog states
4040
const addToProjectDialogOpen = ref(false);
4141
const paperToAdd = ref<Paper | null>(null);
4242
const selectedProjectIdForAdd = ref<number | null>(null);
43-
4443
const pdfViewerOpen = ref(false);
4544
const pdfPaperId = ref<number | null>(null);
4645
const pdfPaperTitle = ref('');
4746
48-
// derived state
47+
// ----- derived state -----
4948
const isAuthenticated = computed(() => authStore.isAuthenticated);
5049
const projects = computed(() => projectsStore.projects);
5150
const projectOptions = computed(() => projectsStore.projects);
5251
53-
onMounted(() => {
52+
// ----- lifecycle -----
53+
54+
onMounted(async () => {
5455
if (isAuthenticated.value) {
5556
projectsStore.loadProjects();
5657
}
58+
// Trigger search immediately based on URL or State
59+
await initializeSearch();
5760
});
5861
59-
// ----- search flow -----
60-
type SearchPayload = { query: string; file: File | null };
61-
62-
function isSearchPayload(payload: unknown): payload is SearchPayload {
63-
return (
64-
!!payload && typeof payload === 'object' &&
65-
'query' in payload &&
66-
typeof (payload as any).query === 'string' &&
67-
'file' in payload &&
68-
(((payload as any).file === null) || (payload as any).file instanceof File)
69-
);
70-
}
62+
// Watch for URL changes (e.g., user searches for something new inside the results page)
63+
watch(() => route.query.q, async (newQuery) => {
64+
if (newQuery !== currentQueryText.value) {
65+
await initializeSearch();
66+
}
67+
});
7168
72-
const handleSubmitQuery = async (payload: { query: string; file: File | null } | string) => {
73-
const query = typeof payload === 'string' ? payload : payload.query;
74-
const file = isSearchPayload(payload) ? payload.file : null;
69+
// ----- search logic -----
70+
71+
const initializeSearch = async () => {
72+
// 1. Check history state for a File (passed from Home)
73+
const stateFile = history.state?.file as File | undefined;
74+
// 2. Check URL query for text
75+
const queryParam = route.query.q?.toString() || '';
76+
77+
// If we have neither, usually we redirect to home, but let's just stay empty or load default
78+
if (!queryParam && !stateFile) {
79+
return;
80+
}
81+
82+
await performSearch(queryParam, stateFile || null);
83+
};
7584
76-
// Update state
77-
currentQueryText.value = query || '';
78-
currentFile.value = file || null;
79-
hasActiveSearch.value = true;
85+
const performSearch = async (query: string, file: File | null) => {
86+
currentQueryText.value = query;
87+
currentFile.value = file;
8088
8189
outputs.value = [];
8290
errorMessage.value = null;
8391
isLoading.value = true;
8492
8593
try {
8694
let response;
87-
8895
if (file) {
8996
response = await searchPapersByPdf(file, query || undefined);
9097
} else {
@@ -99,13 +106,24 @@ const handleSubmitQuery = async (payload: { query: string; file: File | null } |
99106
}
100107
};
101108
102-
// ----- add-from-search flow -----
109+
// Handle new search from within the Results Page
110+
const handleUpdateQuery = (payload: { query: string; file: File | null } | string) => {
111+
const query = typeof payload === 'string' ? payload : payload.query;
112+
const file = typeof payload !== 'string' && payload.file ? payload.file : null;
103113
104-
const handleAddFromSearch = (paper: Paper) => {
105-
if (!isAuthenticated.value || !projects.value.length) {
106-
return;
114+
// Update URL. This will trigger the `watch` above if only text changes.
115+
// If file changes, we might need to manually trigger because URL might not change.
116+
router.push({ query: { q: query }, state: { file: file } });
117+
118+
// If there is a file, the URL watch might not catch it (if query string is same),
119+
// so we force execution if a file is present.
120+
if (file) {
121+
performSearch(query, file);
107122
}
123+
};
108124
125+
const handleAddFromSearch = (paper: Paper) => {
126+
if (!isAuthenticated.value || !projects.value.length) return;
109127
paperToAdd.value = paper;
110128
selectedProjectIdForAdd.value = projects.value[0]?.project_id ?? null;
111129
addToProjectDialogOpen.value = true;
@@ -116,12 +134,7 @@ const confirmAddToProject = async () => {
116134
addToProjectDialogOpen.value = false;
117135
return;
118136
}
119-
120-
await projectsStore.addPaper(
121-
selectedProjectIdForAdd.value,
122-
paperToAdd.value.paper_id
123-
);
124-
137+
await projectsStore.addPaper(selectedProjectIdForAdd.value, paperToAdd.value.paper_id);
125138
addToProjectDialogOpen.value = false;
126139
paperToAdd.value = null;
127140
};
@@ -143,21 +156,16 @@ const handleViewPaper = (paper: Paper) => {
143156
{{ errorMessage }}
144157
</v-alert>
145158

146-
<div v-if="!hasActiveSearch">
147-
<SearchInputSection @submit="handleSubmitQuery" />
148-
</div>
149-
<div v-else>
150-
<SearchResultsSection
151-
:query="currentQueryText"
152-
:file="currentFile"
153-
:outputs="outputs"
154-
:show-abstract="true"
155-
:show-add="isAuthenticated"
156-
@add="handleAddFromSearch"
157-
@view="handleViewPaper"
158-
@update-query="handleSubmitQuery"
159-
/>
160-
</div>
159+
<SearchResultsSection
160+
:query="currentQueryText"
161+
:file="currentFile"
162+
:outputs="outputs"
163+
:show-abstract="true"
164+
:show-add="isAuthenticated"
165+
@add="handleAddFromSearch"
166+
@view="handleViewPaper"
167+
@update-query="handleUpdateQuery"
168+
/>
161169

162170
<v-dialog v-model="addToProjectDialogOpen" max-width="500">
163171
<v-card>

frontend/src/router/index.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { createRouter, createWebHistory } from 'vue-router';
2+
import HomePage from '@/pages/HomePage.vue';
23
import SearchPage from '@/pages/SearchPage.vue';
34
import ProjectPage from '@/pages/ProjectPage.vue';
45

@@ -7,7 +8,12 @@ const router = createRouter({
78
routes: [
89
{
910
path: '/',
10-
redirect: '/search',
11+
redirect: '/home',
12+
},
13+
{
14+
path: '/home',
15+
name: 'home',
16+
component: HomePage,
1117
},
1218
{
1319
path: '/search',
@@ -23,4 +29,4 @@ const router = createRouter({
2329
],
2430
});
2531

26-
export default router;
32+
export default router;

0 commit comments

Comments
 (0)