diff --git a/adonisrc.ts b/adonisrc.ts index a2d8852..edd4ac4 100644 --- a/adonisrc.ts +++ b/adonisrc.ts @@ -1,4 +1,4 @@ -import { defineConfig } from '@adonisjs/core/app'; +import { defineConfig } from '@adonisjs/core/app' export default defineConfig({ /* @@ -13,6 +13,7 @@ export default defineConfig({ commands: [ () => import('@adonisjs/core/commands'), () => import('@adonisjs/lucid/commands'), + () => import('@izzyjs/route/commands'), ], /* @@ -42,6 +43,8 @@ export default defineConfig({ () => import('@adonisjs/auth/auth_provider'), () => import('@adonisjs/inertia/inertia_provider'), () => import('@adonisjs/ally/ally_provider'), + () => import('@izzyjs/route/izzy_provider'), + () => import('#providers/route_provider') ], /* @@ -102,5 +105,6 @@ export default defineConfig({ assetsBundler: false, unstable_assembler: { onBuildStarting: [() => import('@adonisjs/vite/build_hook')], + onDevServerStarted: [() => import('@izzyjs/route/dev_hook')], }, -}); +}) diff --git a/package-lock.json b/package-lock.json index 7435d0f..895d8aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", "@inertiajs/react": "^1.0.16", + "@izzyjs/route": "^1.1.0-0", "@vinejs/vine": "^2.0.0", "edge.js": "^6.0.2", "i18next": "^23.11.3", @@ -1905,6 +1906,18 @@ "react": "^16.9.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/@izzyjs/route": { + "version": "1.1.0-0", + "resolved": "https://registry.npmjs.org/@izzyjs/route/-/route-1.1.0-0.tgz", + "integrity": "sha512-+I9gMZlQANIdIPPa1Pys2tUtzSGKSOKpGBM+Womhwi1rlMp03jsuAGCL1NvZ76M0RKWwrI9lRE7q5qyvZIOXYg==", + "engines": { + "node": ">=20.6.0" + }, + "peerDependencies": { + "@adonisjs/core": "^6.2.0", + "edge.js": "^6.0.2" + } + }, "node_modules/@japa/assert": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@japa/assert/-/assert-3.0.0.tgz", diff --git a/package.json b/package.json index 7fcf36c..d059111 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", "@inertiajs/react": "^1.0.16", + "@izzyjs/route": "^1.1.0-0", "@vinejs/vine": "^2.0.0", "edge.js": "^6.0.2", "i18next": "^23.11.3", diff --git a/providers/route_provider.ts b/providers/route_provider.ts new file mode 100644 index 0000000..9efdca6 --- /dev/null +++ b/providers/route_provider.ts @@ -0,0 +1,5 @@ +export default class RouteProvider { + async boot() { + await import('../src/extensions.js'); + } +} diff --git a/resources/views/inertia_layout.edge b/resources/views/inertia_layout.edge index c4c812b..b32ea50 100644 --- a/resources/views/inertia_layout.edge +++ b/resources/views/inertia_layout.edge @@ -11,6 +11,7 @@ MyLinks + @routes() @inertiaHead() @viteReactRefresh() @vite(['inertia/app/app.tsx', `inertia/pages/${page.component}.tsx`]) diff --git a/src/extensions.ts b/src/extensions.ts new file mode 100644 index 0000000..2cfabce --- /dev/null +++ b/src/extensions.ts @@ -0,0 +1,29 @@ +import { Response } from '@adonisjs/core/http'; +import { route } from '@izzyjs/route/client'; +import { RouteName } from '@izzyjs/route/types'; + +type IzzyRouteOptions = { + params?: Record; //Params; + qs?: Record; + prefix?: string; +}; + +declare module '@adonisjs/core/http' { + export interface Response { + redirectToNamedRoute: ( + routeName: RouteName, + options?: IzzyRouteOptions + ) => void; + } +} + +Response.macro( + 'redirectToNamedRoute', + function (this: Response, routeName, options) { + const current = route(routeName, options); + this.redirect().toRoute(current.url, current.params, { + qs: current.qs, + disableRouteLookup: true, + }); + } +); diff --git a/start/kernel.ts b/start/kernel.ts index 609dec0..6f08863 100644 --- a/start/kernel.ts +++ b/start/kernel.ts @@ -29,6 +29,7 @@ server.use([ () => import('@adonisjs/cors/cors_middleware'), () => import('@adonisjs/vite/vite_middleware'), () => import('@adonisjs/inertia/inertia_middleware'), + () => import('@izzyjs/route/izzy_middleware'), ]); /** diff --git a/start/routes.ts b/start/routes.ts index 4ed8908..12bc1da 100644 --- a/start/routes.ts +++ b/start/routes.ts @@ -1,36 +1,5 @@ -import PATHS from '#constants/paths'; -import { middleware } from '#start/kernel'; -import router from '@adonisjs/core/services/router'; - -const LinksController = () => import('#controllers/links_controller'); -const CollectionsController = () => - import('#controllers/collections_controller'); -const UsersController = () => import('#controllers/users_controller'); -const AppsController = () => import('#controllers/apps_controller'); -const FaviconsController = () => import('#controllers/favicons_controller'); - -router.get(PATHS.HOME, [AppsController, 'index']); -router.post('/user/theme', [AppsController, 'updateUserTheme']); -router.get(PATHS.AUTH.LOGIN, [UsersController, 'login']); -router.get(PATHS.AUTH.GOOGLE, [UsersController, 'google']); -router.get('/auth/callback', [UsersController, 'callbackAuth']); -router.get('/favicon', [FaviconsController, 'index']); - -router - .group(() => { - router.get(PATHS.AUTH.LOGOUT, [UsersController, 'logout']); - router.get(PATHS.DASHBOARD, [CollectionsController, 'index']); - - router.get(PATHS.COLLECTION.CREATE, [ - CollectionsController, - 'showCreatePage', - ]); - router.post('/collections', [CollectionsController, 'store']); - - router.get(PATHS.COLLECTION.EDIT, [CollectionsController, 'showEditPage']); - router.put('/collections/:id', [CollectionsController, 'update']); - - router.get(PATHS.LINK.CREATE, [LinksController, 'showCreatePage']); - router.post('/links', [LinksController, 'store']); - }) - .middleware([middleware.auth()]); +import './routes/app.js'; +import './routes/auth.js'; +import './routes/collection.js'; +import './routes/favicon.js'; +import './routes/link.js'; diff --git a/start/routes/app.ts b/start/routes/app.ts new file mode 100644 index 0000000..8af44d2 --- /dev/null +++ b/start/routes/app.ts @@ -0,0 +1,12 @@ +import router from '@adonisjs/core/services/router'; +const AppsController = () => import('#controllers/apps_controller'); + +/** + * All routes for both logged and guest users + */ +router.group(() => { + router.get('/', [AppsController, 'index']).as('home'); + router + .post('/user/theme', [AppsController, 'updateUserTheme']) + .as('user.theme'); +}); diff --git a/start/routes/auth.ts b/start/routes/auth.ts new file mode 100644 index 0000000..4bd2186 --- /dev/null +++ b/start/routes/auth.ts @@ -0,0 +1,28 @@ +import { middleware } from '#start/kernel'; +import router from '@adonisjs/core/services/router'; +const UsersController = () => import('#controllers/users_controller'); + +const ROUTES_PREFIX = '/auth'; + +/** + * Auth routes for unauthicated users + */ +router + .group(() => { + router.get('/login', [UsersController, 'login']).as('auth.login'); + router.get('/google', [UsersController, 'google']).as('auth.google'); + router + .get('/callback', [UsersController, 'callbackAuth']) + .as('auth.callback'); + }) + .prefix(ROUTES_PREFIX); + +/** + * Routes for authenticated users + */ +router + .group(() => { + router.get('/logout', [UsersController, 'logout']).as('auth.logout'); + }) + .middleware([middleware.auth()]) + .prefix(ROUTES_PREFIX); diff --git a/start/routes/collection.ts b/start/routes/collection.ts new file mode 100644 index 0000000..7f52d73 --- /dev/null +++ b/start/routes/collection.ts @@ -0,0 +1,31 @@ +import { middleware } from '#start/kernel'; +import router from '@adonisjs/core/services/router'; +const CollectionsController = () => + import('#controllers/collections_controller'); + +/** + * Routes for authenticated users + */ +router + .group(() => { + router.get('/dashboard', [CollectionsController, 'index']).as('dashboard'); + + router + .group(() => { + router + .get('/create', [CollectionsController, 'showCreatePage']) + .as('collection.create-form'); + router + .post('/', [CollectionsController, 'store']) + .as('collection.create'); + + router + .get('/edit', [CollectionsController, 'showEditPage']) + .as('collection.edit-form'); + router + .put('/:id', [CollectionsController, 'update']) + .as('collection.edit'); + }) + .prefix('/collections'); + }) + .middleware([middleware.auth()]); diff --git a/start/routes/favicon.ts b/start/routes/favicon.ts new file mode 100644 index 0000000..809feff --- /dev/null +++ b/start/routes/favicon.ts @@ -0,0 +1,9 @@ +import router from '@adonisjs/core/services/router'; +const FaviconsController = () => import('#controllers/favicons_controller'); + +/** + * Favicon routes + */ +router.group(() => { + router.get('/favicon', [FaviconsController, 'index']).as('favicon'); +}); diff --git a/start/routes/link.ts b/start/routes/link.ts new file mode 100644 index 0000000..dae866d --- /dev/null +++ b/start/routes/link.ts @@ -0,0 +1,16 @@ +import { middleware } from '#start/kernel'; +import router from '@adonisjs/core/services/router'; +const LinksController = () => import('#controllers/links_controller'); + +/** + * Routes for authenticated users + */ +router + .group(() => { + router + .get('/create', [LinksController, 'showCreatePage']) + .as('link.create-form'); + router.post('/', [LinksController, 'store']).as('link.create'); + }) + .middleware([middleware.auth()]) + .prefix('/links'); diff --git a/tests/bootstrap.ts b/tests/bootstrap.ts index 637ad68..6d62aab 100644 --- a/tests/bootstrap.ts +++ b/tests/bootstrap.ts @@ -3,6 +3,7 @@ import app from '@adonisjs/core/services/app'; import type { Config } from '@japa/runner/types'; import { pluginAdonisJS } from '@japa/plugin-adonisjs'; import testUtils from '@adonisjs/core/services/test_utils'; +import { izzyRoutePlugin } from '@izzyjs/route/plugins/japa'; /** * This file is imported by the "bin/test.ts" entrypoint file @@ -12,7 +13,11 @@ import testUtils from '@adonisjs/core/services/test_utils'; * Configure Japa plugins in the plugins array. * Learn more - https://japa.dev/docs/runner-config#plugins-optional */ -export const plugins: Config['plugins'] = [assert(), pluginAdonisJS(app)]; +export const plugins: Config['plugins'] = [ + assert(), + pluginAdonisJS(app), + izzyRoutePlugin(), +]; /** * Configure lifecycle function to run before and after all the