restructure file tree

This commit is contained in:
renzynx 2022-12-18 08:31:01 +07:00
parent d96d7582c5
commit a85753aa03
49 changed files with 347 additions and 281 deletions

View File

@ -1,101 +0,0 @@
import LoadingPage from '@components/LoadingPage';
import { ROUTES } from '@lib/constants';
import { useRegister } from '@lib/hooks';
import { ServerSettings } from '@lib/types';
import {
Paper,
Stack,
Group,
TextInput,
PasswordInput,
Anchor,
Button,
Text,
} from '@mantine/core';
import { IconUser } from '@tabler/icons';
function SignUpForm({ settings }: { settings: ServerSettings }) {
const { form, loading, register } = useRegister();
if (!settings) {
return <LoadingPage />;
}
return (
<Paper
w={{
base: '95%',
lg: 450,
md: 420,
sm: 450,
xs: 450,
}}
pt="xl"
pb="xl"
pr="lg"
pl="lg"
withBorder={true}
>
{!settings.REGISTRATION_ENABLED ? (
<Text size="xl" weight={500} align="center">
Registration is currently closed, please check back later.
</Text>
) : (
<>
<Text size="xl" weight={500} mb="xl">
Welcome to Bliss V2, sign up with
</Text>
<form onSubmit={form.onSubmit((values) => register(values))}>
<Stack spacing={10}>
<Group spacing={5}>
<Text weight="bold">Credentials</Text>
<IconUser size={20} />
</Group>
{settings.INVITE_MODE && (
<TextInput
{...form.getInputProps('invite')}
withAsterisk
id="invite"
label="Invite Code"
/>
)}
<TextInput
{...form.getInputProps('username')}
id="username"
label="Username"
description="Leave empty to get a random username"
/>
<TextInput
{...form.getInputProps('email')}
id="email"
withAsterisk
label="Email Address"
/>
<PasswordInput
{...form.getInputProps('password')}
withAsterisk
id="password"
label="Password"
/>
<Group pt="lg" position="apart" align="center">
<Anchor href={ROUTES.SIGN_IN} size="xs" color="dimmed">
Already have an account?
</Anchor>
<Button
variant="light"
color="violet"
type="submit"
loading={loading}
>
Sign up
</Button>
</Group>
</Stack>
</form>
</>
)}
</Paper>
);
}
export default SignUpForm;

View File

@ -1,4 +0,0 @@
import SignInForm from './SignInForm';
import SignUpForm from './SignUpForm';
export { SignInForm, SignUpForm };

View File

@ -0,0 +1,32 @@
import LoadingPage from '@components/pages/LoadingPage';
import { ROUTES } from '@lib/constants';
import { useIsAuth } from '@lib/hooks';
import React, { FC, Suspense } from 'react';
import dynamic from 'next/dynamic';
const Layout = dynamic(() => import('..'), { suspense: true });
const ProtectedWrapper: FC<{ children: any; withLayout?: boolean }> = ({
children,
withLayout,
}) => {
const currentUrl =
typeof window !== 'undefined'
? `${window.location.protocol}//${window.location.host}${window.location.pathname}`
: '';
const { data, isLoading } = useIsAuth({
redirectTo: ROUTES.SIGN_IN,
callbackUrl: encodeURIComponent(currentUrl),
});
if (isLoading) return <LoadingPage color="yellow" />;
return withLayout ? (
<Suspense fallback={<LoadingPage color="yellow" />}>
<Layout user={data!}>{children}</Layout>
</Suspense>
) : (
children
);
};
export default ProtectedWrapper;

View File

@ -0,0 +1,38 @@
import { useCreateInvite } from '@lib/hooks/useInviteCode';
import { Invite } from '@lib/types';
import { Stack, Button, Group, PasswordInput, CopyButton } from '@mantine/core';
import React, { FC } from 'react';
const InvitePage: FC<{ invites: Invite[] }> = ({ invites }) => {
const { create, isLoading } = useCreateInvite();
return (
<Stack>
<Button
loading={isLoading}
w={{ base: '100%', lg: '12rem', md: '12rem', sm: '12rem' }}
color="teal"
onClick={() => create()}
>
Create invite
</Button>
{invites.map((invite, idx) => (
<Group key={idx} sx={{ width: '100%' }} spacing={5}>
<PasswordInput
w={{ base: '100%', lg: 420, md: 400, sm: 400 }}
value={invite.token}
/>
<CopyButton value={invite.token}>
{({ copied, copy }) => (
<Button color={copied ? 'teal' : 'blue'} onClick={copy}>
{copied ? 'Copied invite' : 'Copy invite'}
</Button>
)}
</CopyButton>
</Group>
))}
</Stack>
);
};
export default InvitePage;

View File

@ -1,21 +1,11 @@
import { useSetServerSettings } from '@lib/hooks/useSetServerSettings';
import { ServerSettings } from '@lib/types';
import {
Stack,
SegmentedControl,
Button,
Text,
SimpleGrid,
} from '@mantine/core';
import { Stack, Button, SimpleGrid, Switch } from '@mantine/core';
import { showNotification } from '@mantine/notifications';
import React from 'react';
const AdminForm = ({ REGISTRATION_ENABLED, INVITE_MODE }: ServerSettings) => {
const { isLoading, update, form } = useSetServerSettings({
INVITE_MODE: INVITE_MODE.toString(),
REGISTRATION_ENABLED: REGISTRATION_ENABLED.toString(),
});
const ServerPage = (data: ServerSettings) => {
const { isLoading, update, form } = useSetServerSettings(data);
return (
<form
onSubmit={form.onSubmit((values) => {
@ -40,23 +30,23 @@ const AdminForm = ({ REGISTRATION_ENABLED, INVITE_MODE }: ServerSettings) => {
]}
>
<Stack spacing={0}>
<Text fw="bold">Turn on or off site registration </Text>
<SegmentedControl
<Switch
label="Turn on or off user registration."
size="lg"
radius="lg"
onLabel="ON"
offLabel="OFF"
checked={form.values.REGISTRATION_ENABLED}
{...form.getInputProps('REGISTRATION_ENABLED')}
data={[
{ label: 'On', value: 'true' },
{ label: 'Off', value: 'false' },
]}
/>
</Stack>
<Stack spacing={0}>
<Text fw="bold">Enable or disable invite mode on the site</Text>
<SegmentedControl
<Switch
label="Turn on or off invite mode."
size="lg"
radius="lg"
onLabel="ON"
offLabel="OFF"
checked={form.values.INVITE_MODE}
{...form.getInputProps('INVITE_MODE')}
data={[
{ label: 'Enable', value: 'true' },
{ label: 'Disable', value: 'false' },
]}
/>
</Stack>
</SimpleGrid>
@ -73,4 +63,4 @@ const AdminForm = ({ REGISTRATION_ENABLED, INVITE_MODE }: ServerSettings) => {
);
};
export default AdminForm;
export default ServerPage;

View File

@ -0,0 +1,129 @@
import LoadingPage from '@components/pages/LoadingPage';
import { ROUTES } from '@lib/constants';
import { useRegister } from '@lib/hooks';
import { ServerSettings } from '@lib/types';
import {
Paper,
Stack,
Group,
TextInput,
PasswordInput,
Anchor,
Button,
Text,
Center,
Tooltip,
UnstyledButton,
} from '@mantine/core';
import { IconArrowBack, IconUser } from '@tabler/icons';
import router from 'next/router';
function SignUpPage({ settings }: { settings: ServerSettings }) {
const { form, loading, register } = useRegister();
if (!settings) {
return <LoadingPage />;
}
return (
<>
<Tooltip label="Home page">
<UnstyledButton
sx={(t) => ({
position: 'absolute',
top: 15,
left: 15,
background: t.colors.dark[5],
padding: 13,
display: 'grid',
placeItems: 'center',
borderRadius: t.radius.md,
':hover': {
background: t.colors.dark[4],
},
})}
onClick={() => router.push(ROUTES.HOME)}
>
<IconArrowBack />
</UnstyledButton>
</Tooltip>
<Center sx={{ height: '100vh', width: '100vw' }}>
<Paper
w={{
base: '95%',
lg: 450,
md: 420,
sm: 450,
xs: 450,
}}
pt="xl"
pb="xl"
pr="lg"
pl="lg"
withBorder={true}
>
{!settings.REGISTRATION_ENABLED ? (
<Text size="xl" weight={500} align="center">
Registration is currently closed, please check back later.
</Text>
) : (
<>
<Text size="xl" weight={500} mb="xl">
Welcome to Bliss V2, sign up with
</Text>
<form onSubmit={form.onSubmit((values) => register(values))}>
<Stack spacing={10}>
<Group spacing={5}>
<Text weight="bold">Credentials</Text>
<IconUser size={20} />
</Group>
{settings.INVITE_MODE && (
<TextInput
{...form.getInputProps('invite')}
withAsterisk
id="invite"
label="Invite Code"
/>
)}
<TextInput
{...form.getInputProps('username')}
id="username"
label="Username"
description="Leave empty to get a random username"
/>
<TextInput
{...form.getInputProps('email')}
id="email"
withAsterisk
label="Email Address"
/>
<PasswordInput
{...form.getInputProps('password')}
withAsterisk
id="password"
label="Password"
/>
<Group pt="lg" position="apart" align="center">
<Anchor href={ROUTES.SIGN_IN} size="xs" color="dimmed">
Already have an account?
</Anchor>
<Button
variant="light"
color="violet"
type="submit"
loading={loading}
>
Sign up
</Button>
</Group>
</Stack>
</form>
</>
)}
</Paper>
</Center>
</>
);
}
export default SignUpPage;

View File

@ -0,0 +1,4 @@
import SignInForm from './SignInForm';
import SignUpPage from './SignUpPage';
export { SignInForm, SignUpPage };

View File

@ -1,4 +1,4 @@
import LoadingPage from '@components/LoadingPage';
import LoadingPage from '@components/pages/LoadingPage';
import { useGetUserFiles } from '@lib/hooks';
import { IFile } from '@lib/types';
import {

View File

@ -0,0 +1,18 @@
import Navbar from '@layouts/Navbar';
import Hero from './Hero';
import { FC } from 'react';
import { SessionUser } from '@lib/types';
import dynamic from 'next/dynamic';
const Sidebar = dynamic(() => import('@layouts/Sidebar'));
const HomePage: FC<{ user?: SessionUser }> = ({ user }) => {
return (
<>
<Navbar user={user} />
{user && <Sidebar />}
<Hero />
</>
);
};
export default HomePage;

View File

@ -4,12 +4,13 @@ import { IconCheck, IconCloudUpload, IconDownload, IconX } from '@tabler/icons';
import dynamic from 'next/dynamic';
import { useEffect, useRef, useState } from 'react';
import { uploadStyles } from './styles';
import { API_ROUTES, API_URL, CHUNK_SIZE } from '@lib/constants';
import { API_ROUTES, API_URL, CHUNK_SIZE, USER_LIMIT } from '@lib/constants';
import axios from 'axios';
import { useAtom } from 'jotai';
import { userAtom } from '@lib/atoms';
import { showNotification } from '@mantine/notifications';
const ProgressCard = dynamic(() => import('./ProgressCard'));
import { ACCEPT_TYPE } from '@lib/constants';
const UploadZone = () => {
const [user] = useAtom(userAtom);
@ -129,8 +130,14 @@ const UploadZone = () => {
}}
className={classes.dropzone}
radius="md"
// accept={MIME_TYPES}
maxSize={5000 * 1024 ** 2}
accept={ACCEPT_TYPE}
maxSize={
USER_LIMIT(
!!user?.createdAt,
user?.role === 'OWNER' || user?.role === 'ADMIN'
) *
1024 ** 2
}
>
<div style={{ pointerEvents: 'none' }}>
<Group position="center">

View File

@ -1,4 +1,4 @@
import { serializeURL } from './utils';
import { MIME_TYPES } from '@mantine/dropzone';
export enum ROUTES {
HOME = '/',
@ -28,7 +28,7 @@ export enum API_ROUTES {
CHANGE_USERNAME = '/users/change-username',
SEND_VERIFICATION_EMAIL = '/users/verify/send',
VERIFY_EMAIL = '/users/verify',
CHECK_CLOSED = '/auth/check-register',
SERVER_SETTINGS = '/server-settings',
UPDATE_SERVER_SETTINGS = '/admin/server-settings',
INVITE_CODE = '/admin/invites',
}
@ -59,9 +59,7 @@ export const flameshotScript = (token: string) => `
IMAGEPATH="$HOME/Pictures/"
IMAGENAME="$name-$(date +%s%N | sha256sum | base64 | head -c 32 ; echo)"
KEY="${token}"
DOMAIN="${serializeURL(
process.env.NEXT_PUBLIC_API_URL!
)}" # Your upload domain (without http:// or https://)
DOMAIN="${process.env.NEXT_PUBLIC_API_URL}/upload"
flameshot config -f "$IMAGENAME"
flameshot gui -r -p "$IMAGEPATH" > /dev/null
@ -76,28 +74,61 @@ if [ -f "$FILE" ]; then
-H "Accept: application/json" \
-H "User-Agent: ShareX/13.4.0" \
-H "Authorization: $KEY" \
-F "file=@$IMAGEPATH$IMAGENAME.png" "https://$DOMAIN/" | grep -Po '(?<="resource":")[^"]+')
# printf instead of echo as echo appends a newline
-F "file=@$IMAGEPATH$IMAGENAME.png" "$DOMAIN" | grep -Po '(?<="resource":")[^"]+')
printf "%s" "$URL" | xclip -sel clip
rm "$IMAGEPATH$IMAGENAME.png" # Delete the image locally
rm "$IMAGEPATH$IMAGENAME.png"
else
echo "Aborted."
fi
`;
export const MIME_TYPES = [
'image/png',
'image/gif',
'image/jpeg',
'image/svg+xml',
'image/webp',
'audio/ogg',
'audio/wave',
'audio/wav',
'audio/x-wav',
'audio/x-pn-wav',
// export const MIME_TYPES = [
// 'image/png',
// 'image/gif',
// 'image/jpeg',
// 'image/svg+xml',
// 'image/webp',
// 'audio/ogg',
// 'audio/wave',
// 'audio/wav',
// 'audio/x-wav',
// 'audio/x-pn-wav',
// 'audio/mp3',
// 'audio/mpeg',
// ];
export const ACCEPT_TYPE = [
MIME_TYPES.png,
MIME_TYPES.jpeg,
MIME_TYPES.mp4,
MIME_TYPES.svg,
MIME_TYPES.webp,
MIME_TYPES.gif,
MIME_TYPES.zip,
MIME_TYPES.pdf,
MIME_TYPES.docx,
MIME_TYPES.pptx,
MIME_TYPES.xlsx,
'text/plain',
'audio/mp3',
'audio/wav',
'audio/ogg',
'audio/flac',
'audio/aac',
'audio/m4a',
'audio/mp4',
'audio/mpeg',
'audio/webm',
'audio/3gpp',
'audio/3gpp2',
'audio/aac',
'audio/aiff',
'audio/amr',
'audio/basic',
'audio/midi',
'audio/mid',
'audio/m4a',
'video/mp4',
'video/quicktime',
'video/ogg',
@ -114,5 +145,13 @@ export const MIME_TYPES = [
'multipart/x-zip',
];
export const USER_LIMIT = (verified: boolean, admin = false) => {
if (admin) return Infinity;
return verified
? +(process.env.NEXT_PUBLIC_USER_VERIFED_LIMIT ?? 2000)
: +(process.env.NEXT_PUBLIC_USER_NOT_VERIFED_LIMIT ?? 500);
};
export const CHUNK_SIZE =
+(process.env.NEXT_PUBLIC_CHUNK_SIZE ?? 10) * 1024 ** 2; // default: 10mb

View File

@ -7,17 +7,19 @@ import axios from 'axios';
import { useForm } from '@mantine/form';
import { toErrorMap } from '@lib/utils';
export const useSetServerSettings = (initialData: ServerSettings) => {
const form = useForm<ServerSettings>({
initialValues: initialData,
});
export const useSetServerSettings = (initialValues: ServerSettings) => {
const form = useForm<ServerSettings>({ initialValues });
const { data, mutate, isLoading, error } = useMutation(
['server-settings'],
(data: Partial<ServerSettings>) =>
axios
.post(API_URL + API_ROUTES.UPDATE_SERVER_SETTINGS, data, {
withCredentials: true,
})
.post<ServerSettings>(
API_URL + API_ROUTES.UPDATE_SERVER_SETTINGS,
data,
{
withCredentials: true,
}
)
.then((res) => {
updateNotification({
id: 'server-settings',
@ -27,10 +29,7 @@ export const useSetServerSettings = (initialData: ServerSettings) => {
icon: <IconCheck />,
});
form.setValues({
INVITE_MODE: res.data.INVITE_MODE.toString(),
REGISTRATION_ENABLED: res.data.REGISTRATION_ENABLED.toString(),
});
form.setValues({ ...res.data });
return res.data;
})

View File

@ -116,8 +116,8 @@ export interface EmbedSettings {
}
export interface ServerSettings {
REGISTRATION_ENABLED: string;
INVITE_MODE: string;
REGISTRATION_ENABLED: boolean;
INVITE_MODE: boolean;
}
type Token = 'INVITE_CODE' | 'EMAIL_VERIFICATION';

View File

@ -1,4 +1,4 @@
import { NotFoundTitle } from '@components/404Page';
import { NotFoundTitle } from '@pages/404Page';
import React from 'react';
const NotFound = () => {

View File

@ -1,14 +1,10 @@
import { ROUTES } from '@lib/constants';
import { useIsAuth } from '@lib/hooks';
import { CustomAppProps } from '@lib/types';
import { MantineProvider } from '@mantine/core';
import { NotificationsProvider } from '@mantine/notifications';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import dynamic from 'next/dynamic';
import Head from 'next/head';
import { Suspense } from 'react';
const LoadingPage = dynamic(() => import('@components/LoadingPage'));
const Layout = dynamic(() => import('@components/Layout'), { suspense: true });
const ProtectedWrapper = dynamic(() => import('@layouts/ProtectedWrapper'));
export default function App({ Component, pageProps }: CustomAppProps) {
const queryClient = new QueryClient();
@ -34,9 +30,9 @@ export default function App({ Component, pageProps }: CustomAppProps) {
<QueryClientProvider client={queryClient}>
<NotificationsProvider>
{Component.options?.auth ? (
<Auth withLayout={Component.options.withLayout}>
<ProtectedWrapper withLayout={Component.options.withLayout}>
<Component {...pageProps} />
</Auth>
</ProtectedWrapper>
) : (
<Component {...pageProps} />
)}
@ -46,30 +42,3 @@ export default function App({ Component, pageProps }: CustomAppProps) {
</>
);
}
function Auth({
children,
withLayout,
}: {
children: any;
withLayout?: boolean;
}) {
const currentUrl =
typeof window !== 'undefined'
? `${window.location.protocol}//${window.location.host}${window.location.pathname}`
: '';
const { data, isLoading } = useIsAuth({
redirectTo: ROUTES.SIGN_IN,
callbackUrl: encodeURIComponent(currentUrl),
});
if (isLoading) return <LoadingPage color="yellow" />;
return withLayout ? (
<Suspense fallback={<LoadingPage color="yellow" />}>
<Layout user={data!}>{children}</Layout>
</Suspense>
) : (
children
);
}

View File

@ -12,7 +12,7 @@ import {
//! fix weird hydration issue
// TODO: find a better way to fix hydration issue
const SignInForm = dynamic(
() => import('@components/Authentication').then((mod) => mod.SignInForm),
() => import('@components/pages/AuthPage').then((mod) => mod.SignInForm),
{ ssr: false }
);

View File

@ -1,47 +1,22 @@
import { SignUpForm } from '@components/Authentication';
import { API_ROUTES, API_URL, ROUTES } from '@lib/constants';
import { SignUpPage } from '@pages/AuthPage';
import { API_ROUTES, API_URL } from '@lib/constants';
import { ServerSettings } from '@lib/types';
import { Center, Tooltip, UnstyledButton } from '@mantine/core';
import { IconArrowBack } from '@tabler/icons';
import axios from 'axios';
import { InferGetServerSidePropsType, NextPage } from 'next';
import router from 'next/router';
const SignUp: NextPage<
InferGetServerSidePropsType<typeof getServerSideProps>
> = (data) => {
return (
<>
<Tooltip label="Home page">
<UnstyledButton
sx={(t) => ({
position: 'absolute',
top: 15,
left: 15,
background: t.colors.dark[5],
padding: 13,
display: 'grid',
placeItems: 'center',
borderRadius: t.radius.md,
':hover': {
background: t.colors.dark[4],
},
})}
onClick={() => router.push(ROUTES.HOME)}
>
<IconArrowBack />
</UnstyledButton>
</Tooltip>
<Center sx={{ height: '100vh', width: '100vw' }}>
<SignUpForm settings={data} />
</Center>
<SignUpPage settings={data} />
</>
);
};
export const getServerSideProps = async () => {
const resp = await axios.get<ServerSettings>(
API_URL + API_ROUTES.CHECK_CLOSED
API_URL + API_ROUTES.SERVER_SETTINGS
);
return {

View File

@ -1,12 +1,11 @@
import InvitePage from '@components/pages/AdminPage/InvitePage';
import { API_ROUTES, API_URL, APP_NAME } from '@lib/constants';
import { useCreateInvite } from '@lib/hooks/useInviteCode';
import {
CustomNextPage,
Invite,
ServerSettings,
SessionUser,
} from '@lib/types';
import { Button, CopyButton, Group, PasswordInput, Stack } from '@mantine/core';
import axios from 'axios';
import { GetServerSidePropsContext } from 'next';
import Head from 'next/head';
@ -14,39 +13,13 @@ import Head from 'next/head';
const AdminDash: CustomNextPage<ServerSettings & { invites: Invite[] }> = (
data
) => {
const { create, isLoading } = useCreateInvite();
return (
<>
<Head>
<title>{APP_NAME} | Admin</title>
</Head>
<Stack>
<Button
loading={isLoading}
w={{ base: '100%', lg: '12rem', md: '12rem', sm: '12rem' }}
color="teal"
onClick={() => create()}
>
Create invite
</Button>
{data.invites.map((invite, idx) => (
<Group key={idx} sx={{ width: '100%' }} spacing={5}>
<PasswordInput
w={{ base: '100%', lg: 420, md: 400, sm: 400 }}
value={invite.token}
/>
<CopyButton value={invite.token}>
{({ copied, copy }) => (
<Button color={copied ? 'teal' : 'blue'} onClick={copy}>
{copied ? 'Copied invite' : 'Copy invite'}
</Button>
)}
</CopyButton>
</Group>
))}
</Stack>
<InvitePage invites={data.invites} />
</>
);
};

View File

@ -1,13 +1,13 @@
import AdminForm from '@components/Authentication/AdminForm';
import ServerPage from '@pages/AdminPage/ServerPage';
import { API_ROUTES, API_URL } from '@lib/constants';
import { CustomNextPage, SessionUser } from '@lib/types';
import { CustomNextPage, ServerSettings, SessionUser } from '@lib/types';
import axios from 'axios';
import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';
const Owner: CustomNextPage<
InferGetServerSidePropsType<typeof getServerSideProps>
> = ({ data }) => {
return <AdminForm {...data} />;
return <ServerPage {...data} />;
};
export default Owner;
@ -29,7 +29,9 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
};
}
const serverData = await axios.get(API_URL + API_ROUTES.CHECK_CLOSED);
const serverData = await axios.get<ServerSettings>(
API_URL + API_ROUTES.SERVER_SETTINGS
);
return {
props: { data: serverData.data },

View File

@ -1,5 +1,5 @@
import QuickActions from '@components/QuickActions';
import StatisticCard from '@components/StatisticCard';
import QuickActions from '@pages/DashboardPage';
import StatisticCard from '@layouts/StatisticCard';
import { API_ROUTES, API_URL, APP_NAME } from '@lib/constants';
import { CustomNextPage } from '@lib/types';
import { Group } from '@mantine/core';

View File

@ -1,4 +1,4 @@
import UploadZone from '@components/Upload';
import UploadZone from '@pages/UploadPage';
import { APP_NAME } from '@lib/constants';
import { CustomNextPage } from '@lib/types';
import Head from 'next/head';

View File

@ -1,20 +1,15 @@
import Hero from '@components/Hero';
import Navbar from '@components/Layout/Navbar';
import HomePage from '@pages/HomePage';
import { API_ROUTES, API_URL } from '@lib/constants';
import { SessionUser } from '@lib/types';
import axios from 'axios';
import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';
import dynamic from 'next/dynamic';
const Sidebar = dynamic(() => import('@components/Layout/Sidebar'));
const Home = (
props: InferGetServerSidePropsType<typeof getServerSideProps>
) => {
return (
<>
<Navbar user={props?.user} />
{props.user && <Sidebar />}
<Hero />
<HomePage {...props} />
</>
);
};

View File

@ -1,4 +1,4 @@
import ProfilePage from '@components/ProfilePage';
import ProfilePage from '@pages/ProfilePage';
import { APP_NAME } from '@lib/constants';
import { CustomNextPage } from '@lib/types';
import Head from 'next/head';

View File

@ -1,5 +1,5 @@
import EmbedForm from '@components/Settings/EmbedForm';
import EmbedPreview from '@components/Settings/EmbedPreview';
import EmbedForm from '@pages/SettingPage/EmbedForm';
import EmbedPreview from '@pages/SettingPage/EmbedPreview';
import { API_URL, API_ROUTES } from '@lib/constants';
import { useUpdateEmbedSettings } from '@lib/hooks';
import { CustomNextPage, EmbedSettings } from '@lib/types';

View File

@ -18,7 +18,8 @@
"paths": {
"@lib/*": ["lib/*"],
"@components/*": ["components/*"],
"@pages/*": ["pages/*"]
"@pages/*": ["components/pages/*"],
"@layouts/*": ["components/layouts/*"]
}
},
"include": ["next-env.d.ts", "env.d.ts", "**/*.ts", "**/*.tsx"],