Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: use routes constant for all internal paths #1071

Merged
merged 13 commits into from
Oct 26, 2022
8 changes: 6 additions & 2 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
const relayConfig = require('./relay.config');
const { withSentryConfig } = require('@sentry/nextjs');
const withRoutes = require('nextjs-routes/config')();

const moduleExports = {
/** @type {import('next').NextConfig} */
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This gives a nice autocomplete for next config options

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

YESSSSSS

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This gives us a new autocomplete for the config

const nextConfig = {
typescript: {
// Save time in Vercel builds by avoiding a type check.
// This is fine since we do a type check in Github Actions.
Expand Down Expand Up @@ -61,4 +63,6 @@ const sentryWebpackPluginOptions = {
// https://github.com/getsentry/sentry-webpack-plugin#options.
};

module.exports = withSentryConfig(moduleExports, sentryWebpackPluginOptions);
const plugins = [withRoutes, (config) => withSentryConfig(config, sentryWebpackPluginOptions)];

module.exports = () => plugins.reduce((config, plugin) => plugin(config), nextConfig);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Followed the thread here - cyrilwanner/next-compose-plugins#59

134 changes: 134 additions & 0 deletions nextjs-routes.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
// This file will be automatically regenerated when your Next.js server is running.
/* eslint-disable */

// prettier-ignore
declare module "nextjs-routes" {
export type Route =
| { pathname: "/[username]/[collectionId]/[tokenId]"; query: Query<{ "username": string; "collectionId": string; "tokenId": string }> }
| { pathname: "/[username]/[collectionId]"; query: Query<{ "username": string; "collectionId": string }> }
| { pathname: "/[username]"; query: Query<{ "username": string }> }
| { pathname: "/_/components"; query?: Query | undefined }
| { pathname: "/_/reset"; query?: Query | undefined }
| { pathname: "/announcements"; query?: Query | undefined }
| { pathname: "/auth"; query?: Query | undefined }
| { pathname: "/community/[contractAddress]"; query: Query<{ "contractAddress": string }> }
| { pathname: "/community/poap/[contractAddress]"; query: Query<{ "contractAddress": string }> }
| { pathname: "/community/tez/[contractAddress]"; query: Query<{ "contractAddress": string }> }
| { pathname: "/edit"; query?: Query | undefined }
| { pathname: "/gallery/[galleryId]/collection/[collectionId]/edit"; query: Query<{ "galleryId": string; "collectionId": string }> }
| { pathname: "/gallery/[galleryId]/collection/create"; query: Query<{ "galleryId": string }> }
| { pathname: "/gallery/[galleryId]/edit"; query: Query<{ "galleryId": string }> }
| { pathname: "/home"; query?: Query | undefined }
| { pathname: "/"; query?: Query | undefined }
| { pathname: "/maintenance"; query?: Query | undefined }
| { pathname: "/members"; query?: Query | undefined }
| { pathname: "/members/poster"; query?: Query | undefined }
| { pathname: "/membership/general"; query?: Query | undefined }
| { pathname: "/membership/gold"; query?: Query | undefined }
| { pathname: "/membership/silver"; query?: Query | undefined }
| { pathname: "/nuke"; query?: Query | undefined }
| { pathname: "/onboarding/add-user-info"; query?: Query | undefined }
| { pathname: "/onboarding/congratulations"; query?: Query | undefined }
| { pathname: "/onboarding/create"; query?: Query | undefined }
| { pathname: "/onboarding/edit-collection"; query?: Query | undefined }
| { pathname: "/onboarding/organize-collection"; query?: Query | undefined }
| { pathname: "/onboarding/organize-gallery"; query?: Query | undefined }
| { pathname: "/onboarding/welcome"; query?: Query | undefined }
| { pathname: "/opengraph/collection/[collectionId]"; query: Query<{ "collectionId": string }> }
| { pathname: "/opengraph/nft/[tokenId]"; query: Query<{ "tokenId": string }> }
| { pathname: "/opengraph/user/[username]"; query: Query<{ "username": string }> }
| { pathname: "/privacy"; query?: Query | undefined }
| { pathname: "/shop"; query?: Query | undefined }
| { pathname: "/terms"; query?: Query | undefined };

type Query<Params = {}> = Params & { [key: string]: string | string[] | undefined };

type QueryForPathname = {
[K in Route as K["pathname"]]: Exclude<K["query"], undefined>;
};

export type RoutedQuery<P extends Route["pathname"]> = QueryForPathname[P];

export type Locale = undefined;

/**
* A typesafe utility function for generating paths in your application.
*
* route({ pathname: '/foos/[foo]', query: { foo: 'bar' }}) will produce '/foos/bar'.
*/
export declare function route(r: Route): string;
}

// prettier-ignore
declare module "next/link" {
import type { Route } from "nextjs-routes";
import type { LinkProps as NextLinkProps } from "next/dist/client/link";
import type { PropsWithChildren, MouseEventHandler } from "react";
export * from "next/dist/client/link";

type RouteOrQuery = Route | { query?: { [key: string]: string | string[] | undefined } };

export interface LinkProps extends Omit<NextLinkProps, "href" | "locale"> {
href: RouteOrQuery;
locale?: false;
}

declare function Link(
props: PropsWithChildren<LinkProps>
): DetailedReactHTMLElement<
{
onMouseEnter?: MouseEventHandler<Element> | undefined;
onClick: MouseEventHandler;
href?: string | undefined;
ref?: any;
},
HTMLElement
>;

export default Link;
}

// prettier-ignore
declare module "next/router" {
import type { Locale, Route, RoutedQuery } from "nextjs-routes";
import type { NextRouter as Router } from "next/dist/client/router";
export * from "next/dist/client/router";
export { default } from "next/dist/client/router";

type NextTransitionOptions = NonNullable<Parameters<Router["push"]>[2]>;

interface TransitionOptions extends Omit<NextTransitionOptions, 'locale'> {
locale?: false;
};

type RouteOrQuery =
| Route
| { query: { [key: string]: string | string[] | undefined } };

export interface NextRouter<P extends Route["pathname"] = Route["pathname"]>
extends Omit<
Router,
"push" | "replace" | "locale" | "locales" | "defaultLocale" | "domainLocales"
> {
defaultLocale?: undefined;
domainLocales?: undefined;
locale?: Locale;
locales?: undefined;
pathname: P;
push(
url: RouteOrQuery,
as?: string,
options?: TransitionOptions
): Promise<boolean>;
query: RoutedQuery<P>;
replace(
url: RouteOrQuery,
as?: string,
options?: TransitionOptions
): Promise<boolean>;
route: P;
}

export function useRouter<P extends Route["pathname"]>(): NextRouter<P>;
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"lodash.unescape": "^4.0.1",
"mixpanel-browser": "^2.41.0",
"next": "^12.3.0",
"nextjs-routes": "^0.1.5",
"qr-code-styling": "^1.6.0-rc.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
Expand Down
12 changes: 9 additions & 3 deletions pages/[username]/[collectionId]/[tokenId]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import styled from 'styled-components';
import Link from 'next/link';
import { useRouter } from 'next/router';
import useKeyDown from 'hooks/useKeyDown';
import { useCallback } from 'react';
import { useCallback, useMemo } from 'react';
import GalleryRoute from 'scenes/_Router/GalleryRoute';

type NftDetailPageProps = MetaTagProps & {
Expand All @@ -22,7 +22,13 @@ export default function NftDetailPage({ username, collectionId, tokenId }: NftDe

// the default "back" behavior from the NFT Detail Page
// is a redirect to the Collection Page
const collectionRoute = `/${username}/${collectionId}`;
const collectionRoute = useMemo(
() => ({
pathname: '/[username]/[collectionId]',
query: { username, collectionId },
}),
[username, collectionId]
);

const handleReturnToCollectionPage = useCallback(() => {
push(collectionRoute);
Expand All @@ -32,7 +38,7 @@ export default function NftDetailPage({ username, collectionId, tokenId }: NftDe

if (!tokenId) {
// Something went horribly wrong
return <GalleryRedirect to="/" />;
return <GalleryRedirect to={{ pathname: '/' }} />;
}

return (
Expand Down
5 changes: 3 additions & 2 deletions pages/[username]/[collectionId]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { openGraphMetaTags } from 'utils/openGraphMetaTags';
import { graphql, useLazyLoadQuery } from 'react-relay';
import { CollectionIdQuery } from '__generated__/CollectionIdQuery.graphql';
import GalleryRoute from 'scenes/_Router/GalleryRoute';
import { route } from 'nextjs-routes';

type CollectionGalleryProps = MetaTagProps & {
username: string;
Expand All @@ -23,7 +24,7 @@ export default function CollectionGallery({ collectionId, username }: Collection
);

if (!username || !collectionId) {
return <GalleryRedirect to="/" />;
return <GalleryRedirect to={{ pathname: '/' }} />;
}

return <GalleryRoute element={<CollectionGalleryPage queryRef={query} username={username} />} />;
Expand All @@ -37,7 +38,7 @@ export const getServerSideProps: GetServerSideProps<CollectionGalleryProps> = as

if (!username || !collectionId) {
// How could they have possibly gotten to this route without those params
return { redirect: { permanent: false, destination: '/' } };
return { redirect: { permanent: false, destination: route({ pathname: '/' }) } };
}

return {
Expand Down
3 changes: 2 additions & 1 deletion pages/[username]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { graphql } from 'relay-runtime';
import { useLazyLoadQuery } from 'react-relay';
import { UsernameQuery } from '__generated__/UsernameQuery.graphql';
import GalleryRoute from 'scenes/_Router/GalleryRoute';
import { route } from 'nextjs-routes';

type UserGalleryProps = MetaTagProps & {
username: string;
Expand All @@ -31,7 +32,7 @@ export const getServerSideProps: GetServerSideProps<UserGalleryProps> = async ({
return {
redirect: {
permanent: false,
destination: '/',
destination: route({ pathname: '/' }),
},
};

Expand Down
16 changes: 8 additions & 8 deletions pages/_/components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,28 +55,28 @@ export default function DesignPage() {
<Section>
<TitleM>ButtonLink</TitleM>
<Examples>
<ButtonLink href="#">primary</ButtonLink>
<ButtonLink href="#" pending>
<ButtonLink href={{ pathname: '/' }}>primary</ButtonLink>
<ButtonLink href={{ pathname: '/' }} pending>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tbezman Would that work? or do we need a workaround here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem here

primary
</ButtonLink>
<ButtonLink disabled href="#">
<ButtonLink disabled href={{ pathname: '/' }}>
primary
</ButtonLink>
<ButtonLink disabled href="#" pending>
<ButtonLink disabled href={{ pathname: '/' }} pending>
primary
</ButtonLink>
</Examples>
<Examples>
<ButtonLink href="#" variant="secondary">
<ButtonLink href={{ pathname: '/' }} variant="secondary">
secondary
</ButtonLink>
<ButtonLink href="#" variant="secondary" pending>
<ButtonLink href={{ pathname: '/' }} variant="secondary" pending>
secondary
</ButtonLink>
<ButtonLink disabled href="#" variant="secondary">
<ButtonLink disabled href={{ pathname: '/' }} variant="secondary">
secondary
</ButtonLink>
<ButtonLink disabled href="#" variant="secondary" pending>
<ButtonLink disabled href={{ pathname: '/' }} variant="secondary" pending>
secondary
</ButtonLink>
</Examples>
Expand Down
4 changes: 2 additions & 2 deletions pages/community/[contractAddress]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ export default function CommunityPage({ contractAddress }: CommunityPageProps) {

if (!contractAddress) {
// Something went horribly wrong
return <GalleryRedirect to="/" />;
return <GalleryRedirect to={{ pathname: '/' }} />;
}

if (DISABLED_CONTRACTS.includes(contractAddress)) {
return <GalleryRedirect to="/" />;
return <GalleryRedirect to={{ pathname: '/' }} />;
}

return <GalleryRoute element={<CommunityPageScene queryRef={query} />} />;
Expand Down
2 changes: 1 addition & 1 deletion pages/community/poap/[contractAddress]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default function CommunityPage({ contractAddress }: CommunityPageProps) {

if (!contractAddress) {
// Something went horribly wrong
return <GalleryRedirect to="/" />;
return <GalleryRedirect to={{ pathname: '/' }} />;
}

return <GalleryRoute element={<CommunityPageScene queryRef={query} />} />;
Expand Down
2 changes: 1 addition & 1 deletion pages/community/tez/[contractAddress]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default function CommunityPage({ contractAddress }: CommunityPageProps) {

if (!contractAddress) {
// Something went horribly wrong
return <GalleryRedirect to="/" />;
return <GalleryRedirect to={{ pathname: '/' }} />;
}

return <GalleryRoute element={<CommunityPageScene queryRef={query} />} />;
Expand Down
2 changes: 1 addition & 1 deletion pages/edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@ export default function Edit() {
return <NotFound />;
}

return <GalleryRedirect to={`/gallery/${galleryId}/edit`} />;
return <GalleryRedirect to={{ pathname: '/gallery/[galleryId]/edit', query: { galleryId } }} />;
}
8 changes: 6 additions & 2 deletions pages/gallery/[galleryId]/collection/[collectionId]/edit.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useState } from 'react';
import { useCallback, useMemo, useState } from 'react';
import CollectionEditorProvider, {
useCollectionMetadataState,
useStagedCollectionState,
Expand All @@ -17,6 +17,7 @@ import FullPageStep from 'components/Onboarding/FullPageStep';
import { VStack } from 'components/core/Spacer/Stack';
import { useModalActions } from 'contexts/modal/ModalContext';
import GenericActionModal from 'scenes/Modals/GenericActionModal';
import { Route } from 'nextjs-routes';

type Props = {
galleryId: string;
Expand All @@ -41,7 +42,10 @@ function LazyLoadedCollectionEditor({ galleryId, collectionId }: Props) {

const { back, replace } = useRouter();

const editGalleryUrl = `/gallery/${galleryId}/edit`;
const editGalleryUrl = useMemo<Route>(
() => ({ pathname: '/gallery/[galleryId]/edit', query: { galleryId } }),
[galleryId]
);

const canGoBack = useCanGoBack();
const handlePrevious = useCallback(() => {
Expand Down
12 changes: 7 additions & 5 deletions pages/gallery/[galleryId]/collection/create.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useState } from 'react';
import { useCallback, useMemo, useState } from 'react';
import CollectionEditorProvider, {
useCollectionMetadataState,
useStagedCollectionState,
Expand All @@ -16,6 +16,7 @@ import { useCanGoBack } from 'contexts/navigation/GalleryNavigationProvider';
import { createCollectionQuery } from '../../../../__generated__/createCollectionQuery.graphql';
import { VStack } from 'components/core/Spacer/Stack';
import FullPageStep from 'components/Onboarding/FullPageStep';
import { Route } from 'nextjs-routes';

type Props = {
galleryId: string;
Expand All @@ -38,7 +39,10 @@ function LazyLoadedCollectionEditor({ galleryId }: Props) {

const { push, back, replace } = useRouter();

const editGalleryUrl = `/gallery/${galleryId}/edit`;
const editGalleryUrl = useMemo<Route>(
() => ({ pathname: '/gallery/[galleryId]/edit', query: { galleryId } }),
[galleryId]
);

const handleNext = useCallback(() => {
track('Save new collection button clicked');
Expand All @@ -47,9 +51,7 @@ function LazyLoadedCollectionEditor({ galleryId }: Props) {
content: (
<CollectionCreateOrEditForm
onNext={() => {
push({
pathname: editGalleryUrl,
});
push(editGalleryUrl);
}}
galleryId={galleryId}
stagedCollection={stagedCollectionState}
Expand Down
Loading