mirror of
https://github.com/Sonny93/my-links.git
synced 2025-12-08 22:53:25 +00:00
feat: migrate from paths constant to new route management system
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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'] }
|
||||
);
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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 }
|
||||
);
|
||||
|
||||
@@ -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 (
|
||||
<ContentLayout>
|
||||
<a href={PATHS.AUTH.GOOGLE}>Continue with Google</a>
|
||||
</ContentLayout>
|
||||
);
|
||||
}
|
||||
const LoginPage = () => (
|
||||
<ContentLayout>
|
||||
<a href={route('auth.google').url}>Continue with Google</a>
|
||||
</ContentLayout>
|
||||
);
|
||||
export default LoginPage;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -25,6 +25,8 @@ router
|
||||
router
|
||||
.put('/:id', [CollectionsController, 'update'])
|
||||
.as('collection.edit');
|
||||
|
||||
router.get('/delete', () => 'delete').as('collection.delete-form');
|
||||
})
|
||||
.prefix('/collections');
|
||||
})
|
||||
|
||||
@@ -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');
|
||||
|
||||
Reference in New Issue
Block a user