feat: migrate from paths constant to new route management system

This commit is contained in:
Sonny
2024-05-16 18:53:53 +02:00
committed by Sonny
parent 905f0ba1c7
commit 57ed2c5e94
20 changed files with 82 additions and 75 deletions

View File

@@ -22,6 +22,7 @@ FROM base as build
WORKDIR /app
COPY --from=deps /app/node_modules /app/node_modules
ADD . .
RUN node ace izzy:routes
RUN node ace build
# Production stage

View File

@@ -1,31 +1,4 @@
const PATHS = {
AUTH: {
LOGIN: '/login',
LOGOUT: '/auth/logout',
GOOGLE: '/auth/google',
},
HOME: '/',
DASHBOARD: '/dashboard',
SHARED: '/shared',
PRIVACY: '/privacy',
TERMS: '/terms',
ADMIN: '/admin',
COLLECTION: {
CREATE: '/collections/create',
EDIT: '/collections/edit',
REMOVE: '/collections/remove',
},
LINK: {
CREATE: '/link/create',
EDIT: '/link/edit',
REMOVE: '/link/remove',
},
API: {
COLLECTION: '/collections',
LINK: '/api/link',
},
NOT_FOUND: '/404',
SERVER_ERROR: '/505',
AUTHOR: 'https://www.sonny.dev/',
REPO_GITHUB: 'https://github.com/Sonny93/my-links',
EXTENSION:

View File

@@ -1,10 +1,10 @@
import PATHS from '#constants/paths';
import User from '#models/user';
import type { HttpContext } from '@adonisjs/core/http';
import logger from '@adonisjs/core/services/logger';
import { RouteName } from '@izzyjs/route/types';
export default class UsersController {
private redirectTo = PATHS.HOME;
private redirectTo: RouteName = 'auth.login';
login({ inertia }: HttpContext) {
return inertia.render('login');
@@ -17,17 +17,17 @@ export default class UsersController {
if (google.accessDenied()) {
// TODO: translate error messages + show them in UI
session.flash('flash', 'Access was denied');
return response.redirect(this.redirectTo);
return response.redirectToNamedRoute(this.redirectTo);
}
if (google.stateMisMatch()) {
session.flash('flash', 'Request expired. Retry again');
return response.redirect(this.redirectTo);
return response.redirectToNamedRoute(this.redirectTo);
}
if (google.hasError()) {
session.flash('flash', google.getError() || 'Something went wrong');
return response.redirect(this.redirectTo);
return response.redirectToNamedRoute(this.redirectTo);
}
const {
@@ -56,13 +56,13 @@ export default class UsersController {
session.flash('flash', 'Successfully authenticated');
logger.info(`[${user.email}] auth success`);
response.redirect(PATHS.DASHBOARD);
response.redirectToNamedRoute('dashboard');
}
async logout({ auth, response, session }: HttpContext) {
await auth.use('web').logout();
session.flash('flash', 'Successfully disconnected');
logger.info(`[${auth.user?.email}] disconnected successfully`);
response.redirect(this.redirectTo);
response.redirectToNamedRoute(this.redirectTo);
}
}

View File

@@ -1,4 +1,3 @@
import PATHS from '#constants/paths';
import { ExceptionHandler, HttpContext } from '@adonisjs/core/http';
import app from '@adonisjs/core/services/app';
import type {
@@ -38,7 +37,7 @@ export default class HttpExceptionHandler extends ExceptionHandler {
*/
async handle(error: unknown, ctx: HttpContext) {
if (error instanceof errors.E_ROW_NOT_FOUND) {
return ctx.response.redirect(PATHS.DASHBOARD);
return ctx.response.redirectToNamedRoute('dashboard');
}
return super.handle(error, ctx);
}

View File

@@ -1,7 +1,7 @@
import PATHS from '#constants/paths';
import type { Authenticators } from '@adonisjs/auth/types';
import type { HttpContext } from '@adonisjs/core/http';
import type { NextFn } from '@adonisjs/core/types/http';
import { route } from '@izzyjs/route/client';
/**
* Auth middleware is used authenticate HTTP requests and deny
@@ -11,7 +11,7 @@ export default class AuthMiddleware {
/**
* The URL to redirect to, when authentication fails
*/
redirectTo = PATHS.AUTH.LOGIN;
redirectTo = route('auth.login').url;
async handle(
ctx: HttpContext,

View File

@@ -1,6 +1,6 @@
import KEYS from '#constants/keys';
import PATHS from '#constants/paths';
import { router } from '@inertiajs/react';
import { route } from '@izzyjs/route/client';
import { ReactNode } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import useGlobalHotkeys from '~/hooks/use_global_hotkeys';
@@ -13,7 +13,7 @@ export default function BackToDashboard({ children }: { children: ReactNode }) {
useHotkeys(
KEYS.ESCAPE_KEY,
() => {
router.visit(appendCollectionId(PATHS.DASHBOARD, collectionId));
router.visit(appendCollectionId(route('dashboard').url, collectionId));
},
{ enabled: globalHotkeysEnabled, enableOnFormTags: ['INPUT'] }
);

View File

@@ -21,7 +21,7 @@ const LinksWrapper = styled.div({
const CollectionHeaderWrapper = styled.h2(({ theme }) => ({
fontWeight: 400,
color: theme.colors.font,
paddingInline: '0.8em 1.1em',
paddingRight: '1.1em',
display: 'flex',
gap: '0.4em',
alignItems: 'center',

View File

@@ -1,5 +1,5 @@
import PATHS from '#constants/paths';
import type Collection from '#models/collection';
import { route } from '@izzyjs/route/client';
import { BsThreeDotsVertical } from 'react-icons/bs';
import { GoPencil } from 'react-icons/go';
import { IoIosAddCircleOutline } from 'react-icons/io';
@@ -14,16 +14,19 @@ const CollectionControls = ({
collectionId: Collection['id'];
}) => (
<Dropdown label={<BsThreeDotsVertical />} svgSize={18}>
<DropdownItemLink href={PATHS.LINK.CREATE}>
<DropdownItemLink href={route('link.create-form').url}>
<IoIosAddCircleOutline /> Add
</DropdownItemLink>
<DropdownItemLink
href={appendCollectionId(PATHS.COLLECTION.EDIT, collectionId)}
href={appendCollectionId(route('collection.edit-form').url, collectionId)}
>
<GoPencil /> Edit
</DropdownItemLink>
<DropdownItemLink
href={appendCollectionId(PATHS.COLLECTION.REMOVE, collectionId)}
href={appendCollectionId(
route('collection.delete-form').url,
collectionId
)}
danger
>
<IoTrashOutline /> Delete

View File

@@ -1,7 +1,7 @@
import PATHS from '#constants/paths';
import type Link from '#models/link';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { route } from '@izzyjs/route/client';
import { useCallback } from 'react';
import { AiFillStar, AiOutlineStar } from 'react-icons/ai';
import { BsThreeDotsVertical } from 'react-icons/bs';
@@ -48,9 +48,12 @@ export default function LinkControls({ link }: { link: Link }) {
);
const onFavorite = () => {
const editRoute = route('link.edit', {
params: { id: link.id },
});
makeRequest({
url: `${PATHS.API.LINK}/${link.id}`,
method: 'PUT',
url: editRoute.url,
method: editRoute.method,
body: {
name: link.name,
url: link.url,
@@ -80,12 +83,18 @@ export default function LinkControls({ link }: { link: Link }) {
)}
</StartItem>
<DropdownItemLink
href={appendCollectionId(PATHS.LINK.EDIT, link.collectionId)}
href={appendCollectionId(
route('link.edit-form').url,
link.collectionId
)}
>
<GoPencil /> Edit
</DropdownItemLink>
<DropdownItemLink
href={appendCollectionId(PATHS.LINK.REMOVE, link.collectionId)}
href={appendCollectionId(
route('link.delete-form').url,
link.collectionId
)}
danger
>
<IoTrashOutline /> Delete

View File

@@ -1,6 +1,6 @@
import PATHS from '#constants/paths';
import styled from '@emotion/styled';
import { Link } from '@inertiajs/react';
import { route } from '@izzyjs/route/client';
import { useTranslation } from 'react-i18next';
import useActiveCollection from '~/hooks/use_active_collection';
import { appendCollectionId } from '~/lib/navigation';
@@ -30,7 +30,9 @@ export function NoCollection() {
return (
<NoCollectionStyle>
<Text>{t('select-collection')}</Text>
<Link href={PATHS.COLLECTION.CREATE}>{t('or-create-one')}</Link>
<Link href={route('collection.create-form').url}>
{t('or-create-one')}
</Link>
</NoCollectionStyle>
);
}
@@ -51,7 +53,12 @@ export function NoLink() {
),
}}
/>
<Link href={appendCollectionId(PATHS.LINK.CREATE, activeCollection?.id)}>
<Link
href={appendCollectionId(
route('link.create-form').url,
activeCollection?.id
)}
>
{t('link.create')}
</Link>
</NoCollectionStyle>

View File

@@ -4,6 +4,7 @@ import { Link } from '@inertiajs/react';
import { useTranslation } from 'react-i18next';
import ExternalLink from '~/components/common/external_link';
import packageJson from '../../../package.json';
import { route } from '@izzyjs/route/client';
const FooterStyle = styled.footer(({ theme }) => ({
fontSize: '0.9em',
@@ -21,9 +22,9 @@ export default function Footer() {
return (
<FooterStyle>
<div className="row">
<Link href={PATHS.PRIVACY}>{t('privacy')}</Link>
<Link href={route('privacy').url}>{t('privacy')}</Link>
{' • '}
<Link href={PATHS.TERMS}>{t('terms')}</Link>
<Link href={route('terms').url}>{t('terms')}</Link>
{' • '}
<ExternalLink href={PATHS.EXTENSION}>Extension</ExternalLink>
</div>

View File

@@ -1,11 +1,11 @@
import styled from '@emotion/styled';
import { Link } from '@inertiajs/react';
import { route } from '@izzyjs/route/client';
import { FormEvent, ReactNode } from 'react';
import Button from '~/components/common/form/_button';
import Form from '~/components/common/form/_form';
import BaseLayout from './_base_layout';
import { appendCollectionId } from '~/lib/navigation';
import PATHS from '#constants/paths';
import BaseLayout from './_base_layout';
const FormLayoutStyle = styled.div(({ theme }) => ({
height: 'fit-content',
@@ -49,7 +49,7 @@ const FormLayout = ({
</Button>
</Form>
{!disableHomeLink && (
<Link href={appendCollectionId(PATHS.DASHBOARD, collectionId)}>
<Link href={appendCollectionId(route('dashboard').url, collectionId)}>
Back to home
</Link>
)}

View File

@@ -1,5 +1,6 @@
import styled from '@emotion/styled';
import { Link } from '@inertiajs/react';
import { route } from '@izzyjs/route/client';
import { IoIosLogOut } from 'react-icons/io';
import Dropdown from '~/components/common/dropdown/dropdown';
import { DropdownItemLink } from '~/components/common/dropdown/dropdown_item';
@@ -50,7 +51,7 @@ export default function Navbar() {
<Nav>
<NavList>
<li>
<Link href={PATHS.HOME} css={{ fontSize: '24px' }}>
<Link href={route('home').url} css={{ fontSize: '24px' }}>
MyLinks
</Link>
</li>
@@ -70,7 +71,7 @@ export default function Navbar() {
{isAuthenticated && !!user ? (
<>
<li>
<Link href={PATHS.DASHBOARD}>Dashboard</Link>
<Link href={route('dashboard').url}>Dashboard</Link>
</li>
<li>
<Dropdown
@@ -85,7 +86,7 @@ export default function Navbar() {
</UserCard>
}
>
<DropdownItemLink href={PATHS.AUTH.LOGOUT} danger>
<DropdownItemLink href={route('auth.logout').url} danger>
<IoIosLogOut /> Logout
</DropdownItemLink>
</Dropdown>
@@ -93,7 +94,7 @@ export default function Navbar() {
</>
) : (
<li>
<Link href={PATHS.AUTH.LOGIN}>Login</Link>
<Link href={route('auth.login').url}>Login</Link>
</li>
)}
</NavList>

View File

@@ -1,6 +1,7 @@
import PATHS from '#constants/paths';
import Collection from '#models/collection';
import Link from '#models/link';
import { route } from '@izzyjs/route/client';
import { appendCollectionId } from '~/lib/navigation';
import { SearchItem, SearchResult } from '~/types/search';
export function buildSearchItem(
@@ -13,7 +14,7 @@ export function buildSearchItem(
url:
type === 'link'
? (item as Link).url
: `${PATHS.DASHBOARD}?collectionId=${item.id}`,
: appendCollectionId(route('dashboard').url, item.id),
type,
collection: type === 'link' ? (item as Link).collection : undefined,
};

View File

@@ -1,5 +1,4 @@
import KEYS from '#constants/keys';
import PATHS from '#constants/paths';
import type Collection from '#models/collection';
import Link from '#models/link';
import styled from '@emotion/styled';
@@ -116,14 +115,16 @@ function DashboardProviders(
useHotkeys(
KEYS.OPEN_CREATE_LINK_KEY,
() => {
router.visit(`${PATHS.LINK.CREATE}?collectionId=${activeCollection?.id}`);
router.visit(
appendCollectionId(route('link.create-form').url, activeCollection?.id)
);
},
{ enabled: globalHotkeysEnabled }
);
useHotkeys(
KEYS.OPEN_CREATE_COLLECTION_KEY,
() => {
router.visit(PATHS.COLLECTION.CREATE);
router.visit(route('collection.create-form').url);
},
{ enabled: globalHotkeysEnabled }
);

View File

@@ -1,10 +1,9 @@
import { route } from '@izzyjs/route/client';
import ContentLayout from '~/components/layouts/content_layout';
import PATHS from '../../app/constants/paths';
export default function LoginPage() {
return (
const LoginPage = () => (
<ContentLayout>
<a href={PATHS.AUTH.GOOGLE}>Continue with Google</a>
<a href={route('auth.google').url}>Continue with Google</a>
</ContentLayout>
);
}
);
export default LoginPage;

View File

@@ -20,6 +20,8 @@ declare module '@adonisjs/core/http' {
Response.macro(
'redirectToNamedRoute',
function (this: Response, routeName, options) {
// TODO: fix this
// @ts-ignore
const current = route(routeName, options);
this.redirect().toRoute(current.url, current.params, {
qs: current.qs,

View File

@@ -6,6 +6,9 @@ const AppsController = () => import('#controllers/apps_controller');
*/
router.group(() => {
router.get('/', [AppsController, 'index']).as('home');
router.get('/privacy', () => 'privacy').as('privacy');
router.get('/terms', () => 'terms').as('terms');
router
.post('/user/theme', [AppsController, 'updateUserTheme'])
.as('user.theme');

View File

@@ -25,6 +25,8 @@ router
router
.put('/:id', [CollectionsController, 'update'])
.as('collection.edit');
router.get('/delete', () => 'delete').as('collection.delete-form');
})
.prefix('/collections');
})

View File

@@ -11,6 +11,11 @@ router
.get('/create', [LinksController, 'showCreatePage'])
.as('link.create-form');
router.post('/', [LinksController, 'store']).as('link.create');
router.get('/edit', () => 'edit form').as('link.edit-form');
router.put('/:id', () => 'edit route api').as('link.edit');
router.get('/delete', () => 'delete').as('link.delete-form');
})
.middleware([middleware.auth()])
.prefix('/links');