diff --git a/apps/frontend/eslint.config.mjs b/apps/frontend/eslint.config.mjs
new file mode 100644
index 00000000..6d22b8ee
--- /dev/null
+++ b/apps/frontend/eslint.config.mjs
@@ -0,0 +1,18 @@
+import nextCoreWebVitals from "eslint-config-next/core-web-vitals";
+import nextTypescript from "eslint-config-next/typescript";
+
+const eslintConfig = [
+ ...nextCoreWebVitals,
+ ...nextTypescript,
+ {
+ ignores: [
+ "node_modules/**",
+ ".next/**",
+ "out/**",
+ "build/**",
+ "next-env.d.ts",
+ ],
+ },
+];
+
+export default eslintConfig;
diff --git a/apps/frontend/src/app/(app)/(preview)/p/[id]/page.tsx b/apps/frontend/src/app/(app)/(preview)/p/[id]/page.tsx
index 85f7aa9a..e882fff8 100644
--- a/apps/frontend/src/app/(app)/(preview)/p/[id]/page.tsx
+++ b/apps/frontend/src/app/(app)/(preview)/p/[id]/page.tsx
@@ -10,32 +10,30 @@ import utc from 'dayjs/plugin/utc';
import { VideoOrImage } from '@gitroom/react/helpers/video.or.image';
import { CopyClient } from '@gitroom/frontend/components/preview/copy.client';
import { getT } from '@gitroom/react/translation/get.translation.service.backend';
-import dynamicLoad from 'next/dynamic';
-
-const RenderPreviewDate = dynamicLoad(
- () =>
- import('@gitroom/frontend/components/preview/render.preview.date').then(
- (mod) => mod.RenderPreviewDate
- ),
- { ssr: false }
-);
+import { RenderPreviewDateClient } from '@gitroom/frontend/components/preview/render.preview.date.client';
dayjs.extend(utc);
export const metadata: Metadata = {
title: `${isGeneralServerSide() ? 'Postiz' : 'Gitroom'} Preview`,
description: '',
};
-export default async function Auth({
- params: { id },
- searchParams,
-}: {
- params: {
- id: string;
- };
- searchParams?: {
- share?: string;
- };
-}) {
+export default async function Auth(
+ props: {
+ params: Promise<{
+ id: string;
+ }>;
+ searchParams?: Promise<{
+ share?: string;
+ }>;
+ }
+) {
+ const searchParams = await props.searchParams;
+ const params = await props.params;
+
+ const {
+ id
+ } = params;
+
const post = await (await internalFetch(`/public/posts/${id}`)).json();
const t = await getT();
if (!post.length) {
@@ -102,7 +100,7 @@ export default async function Auth({
)}
{t('publication_date', 'Publication Date:')}{' '}
-
+
diff --git a/apps/frontend/src/app/(app)/(site)/settings/page.tsx b/apps/frontend/src/app/(app)/(site)/settings/page.tsx
index a4cf94f4..5a84f270 100644
--- a/apps/frontend/src/app/(app)/(site)/settings/page.tsx
+++ b/apps/frontend/src/app/(app)/(site)/settings/page.tsx
@@ -6,12 +6,11 @@ export const metadata: Metadata = {
title: `${isGeneralServerSide() ? 'Postiz' : 'Gitroom'} Settings`,
description: '',
};
-export default async function Index({
- searchParams,
-}: {
- searchParams: {
+export default async function Index(props: {
+ searchParams: Promise<{
code: string;
- };
+ }>;
}) {
+ const searchParams = await props.searchParams;
return ;
}
diff --git a/apps/frontend/src/app/(app)/api/uploads/[[...path]]/route.ts b/apps/frontend/src/app/(app)/api/uploads/[[...path]]/route.ts
index 6cc55e1b..b1abf686 100644
--- a/apps/frontend/src/app/(app)/api/uploads/[[...path]]/route.ts
+++ b/apps/frontend/src/app/(app)/api/uploads/[[...path]]/route.ts
@@ -19,16 +19,17 @@ function iteratorToStream(iterator: any) {
},
});
}
-export const GET = (
+export const GET = async (
request: NextRequest,
context: {
- params: {
- path: string[];
- };
+ params: Promise<{
+ path?: string[];
+ }>;
}
) => {
+ const { path } = await context.params;
const filePath =
- process.env.UPLOAD_DIRECTORY + '/' + context.params.path.join('/');
+ process.env.UPLOAD_DIRECTORY + '/' + (path ?? []).join('/');
const response = createReadStream(filePath);
const fileStats = statSync(filePath);
const contentType = mime.getType(filePath) || 'application/octet-stream';
diff --git a/apps/frontend/src/app/(app)/auth/forgot/[token]/page.tsx b/apps/frontend/src/app/(app)/auth/forgot/[token]/page.tsx
index b536e3a0..fbcbfa07 100644
--- a/apps/frontend/src/app/(app)/auth/forgot/[token]/page.tsx
+++ b/apps/frontend/src/app/(app)/auth/forgot/[token]/page.tsx
@@ -7,9 +7,9 @@ export const metadata: Metadata = {
description: '',
};
export default async function Auth(params: {
- params: {
+ params: Promise<{
token: string;
- };
+ }>;
}) {
- return ;
+ return ;
}
diff --git a/apps/frontend/src/app/(app)/auth/page.tsx b/apps/frontend/src/app/(app)/auth/page.tsx
index 6b2d0c6d..d5e6847e 100644
--- a/apps/frontend/src/app/(app)/auth/page.tsx
+++ b/apps/frontend/src/app/(app)/auth/page.tsx
@@ -10,13 +10,13 @@ export const metadata: Metadata = {
title: `${isGeneralServerSide() ? 'Postiz' : 'Gitroom'} Register`,
description: '',
};
-export default async function Auth(params: {searchParams: {provider: string}}) {
+export default async function Auth(params: {searchParams: Promise<{provider: string}>}) {
const t = await getT();
if (process.env.DISABLE_REGISTRATION === 'true') {
const canRegister = (
await (await internalFetch('/auth/can-register')).json()
).register;
- if (!canRegister && !params?.searchParams?.provider) {
+ if (!canRegister && !(await params?.searchParams)?.provider) {
return (
<>
diff --git a/apps/frontend/src/app/(app)/integrations/social/[provider]/page.tsx b/apps/frontend/src/app/(app)/integrations/social/[provider]/page.tsx
index 57d207bf..3022d2ac 100644
--- a/apps/frontend/src/app/(app)/integrations/social/[provider]/page.tsx
+++ b/apps/frontend/src/app/(app)/integrations/social/[provider]/page.tsx
@@ -3,15 +3,21 @@ import { cookies } from 'next/headers';
export const dynamic = 'force-dynamic';
-export default async function Page({
- params: { provider },
- searchParams,
-}: {
- params: {
- provider: string;
- };
- searchParams: any;
-}) {
- const get = cookies().get('auth');
+export default async function Page(
+ props: {
+ params: Promise<{
+ provider: string;
+ }>;
+ searchParams: Promise;
+ }
+) {
+ const searchParams = await props.searchParams;
+ const params = await props.params;
+
+ const {
+ provider
+ } = params;
+
+ const get = (await cookies()).get('auth');
return ;
}
diff --git a/apps/frontend/src/app/(app)/layout.tsx b/apps/frontend/src/app/(app)/layout.tsx
index 861814c2..eb5a8834 100644
--- a/apps/frontend/src/app/(app)/layout.tsx
+++ b/apps/frontend/src/app/(app)/layout.tsx
@@ -34,7 +34,7 @@ const jakartaSans = Plus_Jakarta_Sans({
});
export default async function AppLayout({ children }: { children: ReactNode }) {
- const allHeaders = headers();
+ const allHeaders = await headers();
const Plausible = !!process.env.STRIPE_PUBLISHABLE_KEY
? PlausibleProvider
: Fragment;
diff --git a/apps/frontend/src/app/(extension)/modal/[style]/[platform]/page.tsx b/apps/frontend/src/app/(extension)/modal/[style]/[platform]/page.tsx
index e18e1d78..a389d7f2 100644
--- a/apps/frontend/src/app/(extension)/modal/[style]/[platform]/page.tsx
+++ b/apps/frontend/src/app/(extension)/modal/[style]/[platform]/page.tsx
@@ -1,7 +1,7 @@
'use client';
import { StandaloneModal } from '@gitroom/frontend/components/standalone-modal/standalone.modal';
-export default async function Modal() {
+export default function Modal() {
return (
diff --git a/apps/frontend/src/app/global.scss b/apps/frontend/src/app/global.scss
index f1398562..1f7b72e9 100644
--- a/apps/frontend/src/app/global.scss
+++ b/apps/frontend/src/app/global.scss
@@ -1,6 +1,10 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
+
+@keyframes spin {
+ to { transform: rotate(360deg); }
+}
@import './colors.scss';
@import './polonto.css';
@import '@uppy/core/dist/style.css';
diff --git a/apps/frontend/src/components/analytics/stars.table.component.tsx b/apps/frontend/src/components/analytics/stars.table.component.tsx
index 476d6657..90b81639 100644
--- a/apps/frontend/src/components/analytics/stars.table.component.tsx
+++ b/apps/frontend/src/components/analytics/stars.table.component.tsx
@@ -16,7 +16,7 @@ import { useRouter, useSearchParams } from 'next/navigation';
import useSWR from 'swr';
import clsx from 'clsx';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
-import ReactLoading from 'react-loading';
+import ReactLoading from '@gitroom/frontend/components/layout/loading';
import { useT } from '@gitroom/react/translation/get.transation.service.client';
export const UpDown: FC<{
diff --git a/apps/frontend/src/components/billing/embedded.billing.tsx b/apps/frontend/src/components/billing/embedded.billing.tsx
index 63a1a267..33217cc6 100644
--- a/apps/frontend/src/components/billing/embedded.billing.tsx
+++ b/apps/frontend/src/components/billing/embedded.billing.tsx
@@ -178,8 +178,8 @@ const StripeInputs: FC<{
fill="none"
>
diff --git a/apps/frontend/src/components/billing/main.billing.component.tsx b/apps/frontend/src/components/billing/main.billing.component.tsx
index c404fd21..9dd8de8c 100644
--- a/apps/frontend/src/components/billing/main.billing.component.tsx
+++ b/apps/frontend/src/components/billing/main.billing.component.tsx
@@ -6,7 +6,7 @@ import { Button } from '@gitroom/react/form/button';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import { Subscription } from '@prisma/client';
import { useDebouncedCallback } from 'use-debounce';
-import ReactLoading from 'react-loading';
+import ReactLoading from '@gitroom/frontend/components/layout/loading';
import { deleteDialog } from '@gitroom/react/helpers/delete.dialog';
import { useToaster } from '@gitroom/react/toaster/toaster';
import dayjs from 'dayjs';
diff --git a/apps/frontend/src/components/launches/add.provider.component.tsx b/apps/frontend/src/components/launches/add.provider.component.tsx
index 0442002a..53de90bd 100644
--- a/apps/frontend/src/components/launches/add.provider.component.tsx
+++ b/apps/frontend/src/components/launches/add.provider.component.tsx
@@ -86,7 +86,7 @@ export const AddProviderButton: FC<{
viewBox="0 0 16 16"
fill="none"
>
-
+
-
+
-
+
{commentsList.map((comment, index) => (
- <>
+
- >
+
))}
diff --git a/apps/frontend/src/components/launches/information.component.tsx b/apps/frontend/src/components/launches/information.component.tsx
index 3c441b69..95ae6cb0 100644
--- a/apps/frontend/src/components/launches/information.component.tsx
+++ b/apps/frontend/src/components/launches/information.component.tsx
@@ -37,7 +37,7 @@ const Invalid: FC = () => {
viewBox="0 0 16 16"
fill="none"
>
-
+
(() => {
setShow(false);
});
- const showRef = useRef();
+ const showRef = useRef(undefined);
// Adjust menu position if it would overflow viewport
useLayoutEffect(() => {
diff --git a/apps/frontend/src/components/layout/check.payment.tsx b/apps/frontend/src/components/layout/check.payment.tsx
index 62917317..35dd866d 100644
--- a/apps/frontend/src/components/layout/check.payment.tsx
+++ b/apps/frontend/src/components/layout/check.payment.tsx
@@ -1,5 +1,5 @@
import { FC, ReactNode, useCallback, useEffect, useState } from 'react';
-import Loading from 'react-loading';
+import Loading from '@gitroom/frontend/components/layout/loading';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import { timer } from '@gitroom/helpers/utils/timer';
import { useToaster } from '@gitroom/react/toaster/toaster';
diff --git a/apps/frontend/src/components/layout/loading.tsx b/apps/frontend/src/components/layout/loading.tsx
index 0aa144e6..a14e4e04 100644
--- a/apps/frontend/src/components/layout/loading.tsx
+++ b/apps/frontend/src/components/layout/loading.tsx
@@ -1,15 +1,39 @@
'use client';
-import ReactLoading from 'react-loading';
import { FC } from 'react';
+
+const Spinner: FC<{
+ type?: string;
+ color?: string;
+ width?: number;
+ height?: number;
+}> = ({ color = '#612bd3', width = 100, height = 100 }) => {
+ const size = Math.min(width, height);
+ const borderWidth = Math.max(2, Math.round(size / 8));
+
+ return (
+
+ );
+};
+
+export { Spinner as default };
+
export const LoadingComponent: FC<{
width?: number;
height?: number;
}> = (props) => {
return (
-
-
+
();
+ const editorRef = useRef(undefined);
const [loading, setLoading] = useState(false);
const uppy = useUppyUploader({
diff --git a/apps/frontend/src/components/new-launch/manage.modal.tsx b/apps/frontend/src/components/new-launch/manage.modal.tsx
index 243da51f..0af6af15 100644
--- a/apps/frontend/src/components/new-launch/manage.modal.tsx
+++ b/apps/frontend/src/components/new-launch/manage.modal.tsx
@@ -694,7 +694,7 @@ const Scrollable: FC<{
scrollClasses: string;
children: ReactNode;
}> = ({ className, scrollClasses, children }) => {
- const ref = useRef();
+ const ref = useRef(undefined);
const hasScroll = useHasScroll(ref);
return (
diff --git a/apps/frontend/src/components/new-launch/providers/linkedin/linkedin.preview.tsx b/apps/frontend/src/components/new-launch/providers/linkedin/linkedin.preview.tsx
index 4c9428ba..0f2ca958 100644
--- a/apps/frontend/src/components/new-launch/providers/linkedin/linkedin.preview.tsx
+++ b/apps/frontend/src/components/new-launch/providers/linkedin/linkedin.preview.tsx
@@ -390,7 +390,7 @@ export const LinkedinPreview: FC<{
viewBox="0 0 18 25"
fill="none"
>
-
+
diff --git a/apps/frontend/src/components/new-launch/select.current.tsx b/apps/frontend/src/components/new-launch/select.current.tsx
index 0792d9c4..402764ab 100644
--- a/apps/frontend/src/components/new-launch/select.current.tsx
+++ b/apps/frontend/src/components/new-launch/select.current.tsx
@@ -16,7 +16,7 @@ import {
useModals,
} from '@gitroom/frontend/components/layout/new-modal';
-export function useHasScroll(ref: RefObject): boolean {
+export function useHasScroll(ref: RefObject): boolean {
const [hasHorizontalScroll, setHasHorizontalScroll] = useState(false);
useEffect(() => {
diff --git a/apps/frontend/src/components/notifications/notification.component.tsx b/apps/frontend/src/components/notifications/notification.component.tsx
index ca8ba299..4b890706 100644
--- a/apps/frontend/src/components/notifications/notification.component.tsx
+++ b/apps/frontend/src/components/notifications/notification.component.tsx
@@ -5,7 +5,7 @@ import useSWR from 'swr';
import { FC, useCallback, useState } from 'react';
import clsx from 'clsx';
import { useClickAway } from '@uidotdev/usehooks';
-import ReactLoading from 'react-loading';
+import ReactLoading from '@gitroom/frontend/components/layout/loading';
import { useT } from '@gitroom/react/translation/get.transation.service.client';
function replaceLinks(text: string) {
const urlRegex =
diff --git a/apps/frontend/src/components/preview/render.preview.date.client.tsx b/apps/frontend/src/components/preview/render.preview.date.client.tsx
new file mode 100644
index 00000000..1587c52a
--- /dev/null
+++ b/apps/frontend/src/components/preview/render.preview.date.client.tsx
@@ -0,0 +1,15 @@
+'use client';
+
+import dynamic from 'next/dynamic';
+
+const RenderPreviewDate = dynamic(
+ () =>
+ import('@gitroom/frontend/components/preview/render.preview.date').then(
+ (mod) => mod.RenderPreviewDate
+ ),
+ { ssr: false }
+);
+
+export const RenderPreviewDateClient = ({ date }: { date: string }) => {
+ return ;
+};
diff --git a/apps/frontend/src/components/settings/github.component.tsx b/apps/frontend/src/components/settings/github.component.tsx
index 50bc937f..1b64ef2f 100644
--- a/apps/frontend/src/components/settings/github.component.tsx
+++ b/apps/frontend/src/components/settings/github.component.tsx
@@ -2,7 +2,7 @@
import Image from 'next/image';
import { Button } from '@gitroom/react/form/button';
-import { FC, useCallback, useEffect, useState } from 'react';
+import { FC, Fragment, useCallback, useEffect, useState } from 'react';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import { deleteDialog } from '@gitroom/react/helpers/delete.dialog';
import { Input } from '@gitroom/react/form/input';
@@ -180,7 +180,7 @@ export const GithubComponent: FC<{
return (
<>
{githubState.map((g) => (
- <>
+
{!g.login ? (
)}
- >
+
))}
{githubState.filter((f) => !f.login).length === 0 && (
diff --git a/apps/frontend/src/components/settings/metric.component.tsx b/apps/frontend/src/components/settings/metric.component.tsx
index 29efeaf5..8869c1f6 100644
--- a/apps/frontend/src/components/settings/metric.component.tsx
+++ b/apps/frontend/src/components/settings/metric.component.tsx
@@ -34,12 +34,11 @@ const MetricComponent = () => {
return (
Date Metrics
-