fix(chatelet): root-relative routes so room deep links and refreshes work #159
5 changed files with 18 additions and 9 deletions
fix(chatelet): root-relative standalone routes for clean room URLs
The chatelet module hardcoded "/chatelet" in its route paths while the
standalone also mounts under a Vite base path ("/chatelet/"), which the
router applies too. The two stacked, so in-app URLs came out
double-prefixed ("/chatelet/chatelet/<id>") and the clean single-prefix
URL ("/chatelet/<id>" — what a person would type or share) matched nothing
and fell back to the room list.
Click-through and refresh already worked on the double-prefixed URL via the
standalone SPA fallback (server-deploy d5f5a19); this is about the URLs
themselves. Make the routes root-relative ("/" list, "/:id" detail,
"/my-bookings") so the base path supplies the single prefix: in-app nav now
produces clean "/chatelet/<id>" URLs, and that shareable form resolves to
the room.
Drop the now-redundant "/" -> "/chatelet" redirect, point the
list/detail/browse links and the Rooms tab at the new paths, and key the
tab's active state off the route name (a "/" prefix test would match
everything).
Verified on a production build served under "/chatelet/" like nginx: the
list, a deep link to a room, a refresh on it, and in-app room clicks all
resolve to the detail page with a single-prefixed URL. vue-tsc build passes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
commit
53327b3ef2
|
|
@ -15,7 +15,7 @@ const { isAuthenticated } = useAuth()
|
|||
// auth-gated the same way events gates My tickets: ghosted when logged out,
|
||||
// and a tap explains instead of bouncing to /login.
|
||||
const tabs = computed<BottomTab[]>(() => [
|
||||
{ name: 'Rooms', icon: BedDouble, path: '/chatelet' },
|
||||
{ name: 'Rooms', icon: BedDouble, path: '/' },
|
||||
{
|
||||
name: 'My bookings',
|
||||
icon: CalendarCheck,
|
||||
|
|
@ -34,6 +34,10 @@ const tabs = computed<BottomTab[]>(() => [
|
|||
])
|
||||
|
||||
function isActive(path: string): boolean {
|
||||
// "/" is the Rooms tab: active on the room list and any room detail
|
||||
// ("/:id"). A prefix test would match every route, so key off the route
|
||||
// name instead.
|
||||
if (path === '/') return route.name === 'chatelet' || route.name === 'chatelet-detail'
|
||||
return route.path === path || route.path.startsWith(path + '/')
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@ export async function createAppInstance() {
|
|||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{ path: '/', redirect: '/chatelet' },
|
||||
// "/" is the room list (chatelet module route). No redirect: the
|
||||
// standalone's base path already scopes every route under it.
|
||||
{
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
|
|
|
|||
|
|
@ -17,7 +17,11 @@ export const chateletModule = createModulePlugin({
|
|||
|
||||
routes: [
|
||||
{
|
||||
path: '/chatelet',
|
||||
// Root-relative: the standalone mounts under a base path (Vite base,
|
||||
// e.g. "/chatelet/") that the router already applies, so hardcoding
|
||||
// "/chatelet" here double-prefixed every URL ("/chatelet/chatelet/…")
|
||||
// and made deep links / refreshes fall back to the list.
|
||||
path: '/',
|
||||
name: 'chatelet',
|
||||
component: () => import('./views/ChateletPage.vue'),
|
||||
meta: {
|
||||
|
|
@ -26,14 +30,14 @@ export const chateletModule = createModulePlugin({
|
|||
},
|
||||
},
|
||||
{
|
||||
path: '/chatelet/:id',
|
||||
path: '/:id',
|
||||
name: 'chatelet-detail',
|
||||
component: () => import('./views/ChateletDetailPage.vue'),
|
||||
meta: { title: 'Room', requiresAuth: false },
|
||||
},
|
||||
{
|
||||
// Mirrors events' /my-tickets; kept off /chatelet/* so it never
|
||||
// collides with the :id room route.
|
||||
// Mirrors events' /my-tickets. A static path, so it ranks above the
|
||||
// "/:id" room route and never resolves as a room id.
|
||||
path: '/my-bookings',
|
||||
name: 'chatelet-my-bookings',
|
||||
component: () => import('./views/MyBookingsPage.vue'),
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ const { rooms, isLoading, loadRooms } = useChatelet()
|
|||
onMounted(loadRooms)
|
||||
|
||||
function open(id: string) {
|
||||
router.push(`/chatelet/${id}`)
|
||||
router.push(`/${id}`)
|
||||
}
|
||||
|
||||
function priceLabel(r: Room): string {
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ function statusBadge(b: GuestBooking): { label: string; variant: BadgeVariant }
|
|||
{{ group.title }}
|
||||
</h2>
|
||||
<Card v-for="b in group.items" :key="b.id" class="overflow-hidden">
|
||||
<RouterLink :to="`/chatelet/${b.room_id}`" class="flex gap-3">
|
||||
<RouterLink :to="`/${b.room_id}`" class="flex gap-3">
|
||||
<img
|
||||
v-if="roomImage(b.room_id)"
|
||||
:src="roomImage(b.room_id)"
|
||||
|
|
@ -113,7 +113,7 @@ function statusBadge(b: GuestBooking): { label: string; variant: BadgeVariant }
|
|||
<CalendarCheck class="mx-auto h-10 w-10 text-muted-foreground" />
|
||||
<p class="text-muted-foreground">No bookings yet.</p>
|
||||
<Button as-child variant="outline">
|
||||
<RouterLink to="/chatelet">Browse rooms</RouterLink>
|
||||
<RouterLink to="/">Browse rooms</RouterLink>
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue