Skip to content

Commit

Permalink
chore(web): migrate to app router (#89)
Browse files Browse the repository at this point in the history
* feat(web): migrate to nextjs app router

* fix: lint

* fix: frontendbuild

* fix: frontend test

* fix: frontend test

* fix: frontend test

* fix: frontend test

* fix: frontend test
  • Loading branch information
tericcabrel committed Jul 14, 2024
1 parent 36bbff0 commit 7349e92
Show file tree
Hide file tree
Showing 111 changed files with 2,392 additions and 1,231 deletions.
7 changes: 7 additions & 0 deletions .changeset/tender-oranges-matter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@snipcode/front': minor
'@snipcode/web': minor
'@snipcode/backend': patch
---

migrate to next.js app router
4 changes: 3 additions & 1 deletion .github/workflows/build-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@ jobs:
run: yarn lint

- name: Build the projects
env:
NEXT_PUBLIC_APP_URL: http://localhost:7500 # Required for the frontend build
run: yarn build

- name: Start MySQL server
run: sudo systemctl start mysql.service

- name: Run tests
run: yarn test -- --runInBand
run: yarn test

version:
runs-on: ubuntu-latest
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ jobs:
run: yarn lint

- name: Build the projects
env:
NEXT_PUBLIC_APP_URL: http://localhost:7500 # Required for the frontend build
run: yarn build

- name: Run tests
run: yarn test -- --runInBand --coverage
run: yarn test -- --coverage

should-preview-frontend:
runs-on: ubuntu-latest
Expand Down
3 changes: 0 additions & 3 deletions apps/backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,6 @@ COPY --chown=node:node --from=builder /app/packages/utils/dist ./packages/utils/
COPY --chown=node:node --from=builder /app/packages/embed/package.json ./packages/embed/package.json
COPY --chown=node:node --from=builder /app/packages/embed/dist ./packages/embed/dist

COPY --chown=node:node --from=builder /app/packages/logger/package.json ./packages/logger/package.json
COPY --chown=node:node --from=builder /app/packages/logger/dist ./packages/logger/dist

RUN yarn workspaces focus --all --production && yarn cache clean --all

COPY --chown=node:node --from=schema-builder /app/node_modules/.prisma/client ./node_modules/.prisma/client
Expand Down
10 changes: 10 additions & 0 deletions apps/web/.env.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_GITHUB_CLIENT_ID=github-client-id
NEXT_PUBLIC_SERVER_URL=http://localhost:7501/graphql
NEXT_PUBLIC_APP_URL=http://localhost:7500
NEXT_PUBLIC_SENTRY_DSN=https://[email protected]/1234567
NEXT_PUBLIC_SENTRY_ENABLED=false
SENTRY_AUTH_TOKEN=
SENTRY_RELEASE=
SHAREABLE_HOST=http://localhost:7500
EMBEDDABLE_HOST=http://localhost:7502
5 changes: 2 additions & 3 deletions apps/web/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,15 @@ module.exports = {
},
},
ignorePatterns: [
'jest.config.ts',
'__mocks__',
'mocks',
'next.config.js',
'tailwind.config.js',
'postcss.config.js',
'next-sitemap.js',
'sentry.client.config.js',
'sentry.server.config.js',
'sentry.edge.config.js',
'.eslintrc.js',
'vitest.config.ts',
],
parserOptions: {
ecmaVersion: 2023,
Expand Down
3 changes: 2 additions & 1 deletion apps/web/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ export type EnvironmentVariables = {

declare global {
namespace NodeJS {
type ProcessEnv = EnvironmentVariables;
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface ProcessEnv extends EnvironmentVariables {}
}
}

Expand Down
24 changes: 0 additions & 24 deletions apps/web/jest.config.ts

This file was deleted.

14 changes: 0 additions & 14 deletions apps/web/next-sitemap.js

This file was deleted.

2 changes: 1 addition & 1 deletion apps/web/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ module.exports = withSentryConfig(nextConfigOptions, {
project: 'frontend',
// release: "[email protected]",
authToken: process.env.SENTRY_AUTH_TOKEN, // An auth token is required for uploading source maps.
silent: false,
silent: true,
telemetry: false,
});
13 changes: 8 additions & 5 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
"dev": "next dev --port 7500",
"lint": "next lint",
"start": "next start",
"test": "jest",
"postbuild": "next-sitemap --config next-sitemap.js"
"test": "dotenv -e .env.test -- vitest"
},
"dependencies": {
"@apollo/client": "3.10.6",
"@apollo/experimental-nextjs-app-support": "0.11.2",
"@headlessui/react": "2.1.0",
"@hookform/resolvers": "3.6.0",
"@sentry/nextjs": "8.11.0",
Expand All @@ -36,14 +36,17 @@
"@testing-library/user-event": "14.5.2",
"@types/react": "18.3.3",
"@types/react-dom": "18.3.0",
"@vitejs/plugin-react": "4.3.1",
"@vitest/coverage-v8": "2.0.2",
"autoprefixer": "10.4.19",
"eslint-config-next": "14.2.4",
"eslint-import-resolver-typescript": "3.6.1",
"eslint-plugin-jest-dom": "5.4.0",
"eslint-plugin-testing-library": "6.2.2",
"next-router-mock": "0.9.13",
"next-sitemap": "4.2.3",
"jsdom": "24.1.0",
"postcss": "8.4.38",
"tailwindcss": "3.4.4"
"tailwindcss": "3.4.4",
"vite-tsconfig-paths": "4.3.2",
"vitest": "2.0.2"
}
}
Binary file added apps/web/public/android-chrome-192x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/web/public/android-chrome-512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/web/public/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/web/public/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/web/public/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified apps/web/public/favicon.ico
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
'use client';

import { Button } from '@snipcode/front/forms/button';
import { SelectInput } from '@snipcode/front/forms/select-input';
import { ChevronDoubleLeftIcon, ChevronDoubleRightIcon, SearchIcon } from '@snipcode/front/icons';
import { usePublicSnippets } from '@snipcode/front/services';
import { SelectOption } from '@snipcode/front/typings/components';
import { PublicSnippetItem, PublicSnippetResult } from '@snipcode/front/typings/queries';
import { NextSeo } from 'next-seo';
import { useState } from 'react';

import { Layout } from '@/components/layout/private/layout';
import { PublicSnippet } from '@/components/snippets/public-snippet';
import { usePaginationToken } from '@/hooks/use-pagination-token';

Expand All @@ -22,7 +22,7 @@ const sortOptions: SelectOption[] = [
{ id: 'recently_updated', label: 'Sort: recently updated' },
];

const Browse = ({ data }: Props) => {
export const BrowseContainer = ({ data }: Props) => {
const [snippetList, setSnippetList] = useState<PublicSnippetItem[]>(data.items);
const [sortOption, setSortOption] = useState<SelectOption>(sortOptions[0]);
const [search, setSearch] = useState<string | undefined>();
Expand Down Expand Up @@ -93,64 +93,59 @@ const Browse = ({ data }: Props) => {
};

return (
<Layout>
<NextSeo title="Browse" />
<div className="py-10">
<main>
<div className="max-w-6xl mx-auto sm:px-6 lg:px-8">
<div className="w-full mx-auto border-b border-gray-400 flex justify-between pb-4">
<div className="relative mt-1 rounded-md shadow-sm w-1/4">
<input
className="block w-full rounded-md border-gray-300 pr-10 sm:text-sm"
id="account-number"
name="account-number"
placeholder="Search..."
type="text"
onChange={(e) => onSearchChange(e.target.value)}
/>
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
<SearchIcon className="h-5 w-5 text-gray-400" />
</div>
</div>
<SelectInput
className="w-1/5 cursor-pointer"
options={sortOptions}
value={sortOption}
onChange={onSortOptionChange}
<div className="py-10">
<main>
<div className="max-w-6xl mx-auto sm:px-6 lg:px-8">
<div className="w-full mx-auto border-b border-gray-400 flex justify-between pb-4">
<div className="relative mt-1 rounded-md shadow-sm w-1/4">
<input
className="block w-full rounded-md border-gray-300 pr-10 sm:text-sm"
id="account-number"
name="account-number"
placeholder="Search..."
type="text"
onChange={(e) => onSearchChange(e.target.value)}
/>
</div>
<div className="px-4 py-8 sm:px-0">
<div className="space-y-6 min-h-96">
{snippetList.map((snippet) => (
<PublicSnippet key={snippet.id} snippet={snippet} />
))}
</div>
<div className="w-full flex justify-center mt-10 space-x-4">
<Button
className="bg-gray-200 w-auto items-center"
color="white-gray"
disabled={!canGoBack}
onClick={onPreviousItemClick}
>
<ChevronDoubleLeftIcon className="w-6 h-4" />
Previous
</Button>
<Button
className="bg-gray-200 w-auto items-center"
color="white-gray"
disabled={!canGoForward}
onClick={onNextItemClick}
>
Next
<ChevronDoubleRightIcon className="w-6 h-4" />
</Button>
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
<SearchIcon className="h-5 w-5 text-gray-400" />
</div>
</div>
<SelectInput
className="w-1/5 cursor-pointer"
options={sortOptions}
value={sortOption}
onChange={onSortOptionChange}
/>
</div>
</main>
</div>
</Layout>
<div className="px-4 py-8 sm:px-0">
<div className="space-y-6 min-h-96">
{snippetList.map((snippet) => (
<PublicSnippet key={snippet.id} snippet={snippet} />
))}
</div>
<div className="w-full flex justify-center mt-10 space-x-4">
<Button
className="bg-gray-200 w-auto items-center"
color="white-gray"
disabled={!canGoBack}
onClick={onPreviousItemClick}
>
<ChevronDoubleLeftIcon className="w-6 h-4" />
Previous
</Button>
<Button
className="bg-gray-200 w-auto items-center"
color="white-gray"
disabled={!canGoForward}
onClick={onNextItemClick}
>
Next
<ChevronDoubleRightIcon className="w-6 h-4" />
</Button>
</div>
</div>
</div>
</main>
</div>
);
};

export { Browse };
31 changes: 31 additions & 0 deletions apps/web/src/app/(protected)/app/browse/lib/fetch-snippets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { findPublicSnippetsQuery } from '@snipcode/front/graphql';
import { PublicSnippetsQuery } from '@snipcode/front/graphql/generated';
import { formatPublicSnippetsResult } from '@snipcode/front/services';
import { SNIPPET_ITEM_PER_PAGE } from '@snipcode/front/utils/constants';
import { cookies } from 'next/headers';

import { getApolloClient } from '@/lib/apollo/server';
import { AUTH_COOKIE_NAME } from '@/lib/constants';
import { logErrorToSentry } from '@/lib/errors';

export const fetchSnippets = async () => {
try {
const authToken = cookies().get(AUTH_COOKIE_NAME);

const { data } = await getApolloClient().query<PublicSnippetsQuery>({
context: {
headers: {
Authorization: authToken?.value,
},
},
query: findPublicSnippetsQuery,
variables: { input: { itemPerPage: SNIPPET_ITEM_PER_PAGE } },
});

return formatPublicSnippetsResult(data);
} catch (error: unknown) {
logErrorToSentry(error);

throw new Error('Failed to fetch public snippets');
}
};
22 changes: 22 additions & 0 deletions apps/web/src/app/(protected)/app/browse/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { generatePageMetadata } from '@/lib/seo';

import { BrowseContainer } from './container';
import { fetchSnippets } from './lib/fetch-snippets';

export const dynamic = 'force-dynamic';

export const metadata = generatePageMetadata({
title: 'Snipcode - Browse code snippets',
});

const BrowsePage = async () => {
const data = await fetchSnippets();

if (!data) {
throw new Error('Failed to fetch public snippets');
}

return <BrowseContainer data={data} />;
};

export default BrowsePage;
Loading

0 comments on commit 7349e92

Please sign in to comment.