mirror of https://github.com/renzynx/bliss.git
restructure file tree
This commit is contained in:
parent
d96d7582c5
commit
a85753aa03
|
@ -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;
|
|
|
@ -1,4 +0,0 @@
|
||||||
import SignInForm from './SignInForm';
|
|
||||||
import SignUpForm from './SignUpForm';
|
|
||||||
|
|
||||||
export { SignInForm, SignUpForm };
|
|
|
@ -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;
|
|
@ -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;
|
|
@ -1,21 +1,11 @@
|
||||||
import { useSetServerSettings } from '@lib/hooks/useSetServerSettings';
|
import { useSetServerSettings } from '@lib/hooks/useSetServerSettings';
|
||||||
import { ServerSettings } from '@lib/types';
|
import { ServerSettings } from '@lib/types';
|
||||||
import {
|
import { Stack, Button, SimpleGrid, Switch } from '@mantine/core';
|
||||||
Stack,
|
|
||||||
SegmentedControl,
|
|
||||||
Button,
|
|
||||||
Text,
|
|
||||||
SimpleGrid,
|
|
||||||
} from '@mantine/core';
|
|
||||||
import { showNotification } from '@mantine/notifications';
|
import { showNotification } from '@mantine/notifications';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const AdminForm = ({ REGISTRATION_ENABLED, INVITE_MODE }: ServerSettings) => {
|
const ServerPage = (data: ServerSettings) => {
|
||||||
const { isLoading, update, form } = useSetServerSettings({
|
const { isLoading, update, form } = useSetServerSettings(data);
|
||||||
INVITE_MODE: INVITE_MODE.toString(),
|
|
||||||
REGISTRATION_ENABLED: REGISTRATION_ENABLED.toString(),
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
onSubmit={form.onSubmit((values) => {
|
onSubmit={form.onSubmit((values) => {
|
||||||
|
@ -40,23 +30,23 @@ const AdminForm = ({ REGISTRATION_ENABLED, INVITE_MODE }: ServerSettings) => {
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Stack spacing={0}>
|
<Stack spacing={0}>
|
||||||
<Text fw="bold">Turn on or off site registration </Text>
|
<Switch
|
||||||
<SegmentedControl
|
label="Turn on or off user registration."
|
||||||
|
size="lg"
|
||||||
|
radius="lg"
|
||||||
|
onLabel="ON"
|
||||||
|
offLabel="OFF"
|
||||||
|
checked={form.values.REGISTRATION_ENABLED}
|
||||||
{...form.getInputProps('REGISTRATION_ENABLED')}
|
{...form.getInputProps('REGISTRATION_ENABLED')}
|
||||||
data={[
|
|
||||||
{ label: 'On', value: 'true' },
|
|
||||||
{ label: 'Off', value: 'false' },
|
|
||||||
]}
|
|
||||||
/>
|
/>
|
||||||
</Stack>
|
<Switch
|
||||||
<Stack spacing={0}>
|
label="Turn on or off invite mode."
|
||||||
<Text fw="bold">Enable or disable invite mode on the site</Text>
|
size="lg"
|
||||||
<SegmentedControl
|
radius="lg"
|
||||||
|
onLabel="ON"
|
||||||
|
offLabel="OFF"
|
||||||
|
checked={form.values.INVITE_MODE}
|
||||||
{...form.getInputProps('INVITE_MODE')}
|
{...form.getInputProps('INVITE_MODE')}
|
||||||
data={[
|
|
||||||
{ label: 'Enable', value: 'true' },
|
|
||||||
{ label: 'Disable', value: 'false' },
|
|
||||||
]}
|
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
|
@ -73,4 +63,4 @@ const AdminForm = ({ REGISTRATION_ENABLED, INVITE_MODE }: ServerSettings) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AdminForm;
|
export default ServerPage;
|
|
@ -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;
|
|
@ -0,0 +1,4 @@
|
||||||
|
import SignInForm from './SignInForm';
|
||||||
|
import SignUpPage from './SignUpPage';
|
||||||
|
|
||||||
|
export { SignInForm, SignUpPage };
|
|
@ -1,4 +1,4 @@
|
||||||
import LoadingPage from '@components/LoadingPage';
|
import LoadingPage from '@components/pages/LoadingPage';
|
||||||
import { useGetUserFiles } from '@lib/hooks';
|
import { useGetUserFiles } from '@lib/hooks';
|
||||||
import { IFile } from '@lib/types';
|
import { IFile } from '@lib/types';
|
||||||
import {
|
import {
|
|
@ -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;
|
|
@ -4,12 +4,13 @@ import { IconCheck, IconCloudUpload, IconDownload, IconX } from '@tabler/icons';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { uploadStyles } from './styles';
|
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 axios from 'axios';
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
import { userAtom } from '@lib/atoms';
|
import { userAtom } from '@lib/atoms';
|
||||||
import { showNotification } from '@mantine/notifications';
|
import { showNotification } from '@mantine/notifications';
|
||||||
const ProgressCard = dynamic(() => import('./ProgressCard'));
|
const ProgressCard = dynamic(() => import('./ProgressCard'));
|
||||||
|
import { ACCEPT_TYPE } from '@lib/constants';
|
||||||
|
|
||||||
const UploadZone = () => {
|
const UploadZone = () => {
|
||||||
const [user] = useAtom(userAtom);
|
const [user] = useAtom(userAtom);
|
||||||
|
@ -129,8 +130,14 @@ const UploadZone = () => {
|
||||||
}}
|
}}
|
||||||
className={classes.dropzone}
|
className={classes.dropzone}
|
||||||
radius="md"
|
radius="md"
|
||||||
// accept={MIME_TYPES}
|
accept={ACCEPT_TYPE}
|
||||||
maxSize={5000 * 1024 ** 2}
|
maxSize={
|
||||||
|
USER_LIMIT(
|
||||||
|
!!user?.createdAt,
|
||||||
|
user?.role === 'OWNER' || user?.role === 'ADMIN'
|
||||||
|
) *
|
||||||
|
1024 ** 2
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<div style={{ pointerEvents: 'none' }}>
|
<div style={{ pointerEvents: 'none' }}>
|
||||||
<Group position="center">
|
<Group position="center">
|
|
@ -1,4 +1,4 @@
|
||||||
import { serializeURL } from './utils';
|
import { MIME_TYPES } from '@mantine/dropzone';
|
||||||
|
|
||||||
export enum ROUTES {
|
export enum ROUTES {
|
||||||
HOME = '/',
|
HOME = '/',
|
||||||
|
@ -28,7 +28,7 @@ export enum API_ROUTES {
|
||||||
CHANGE_USERNAME = '/users/change-username',
|
CHANGE_USERNAME = '/users/change-username',
|
||||||
SEND_VERIFICATION_EMAIL = '/users/verify/send',
|
SEND_VERIFICATION_EMAIL = '/users/verify/send',
|
||||||
VERIFY_EMAIL = '/users/verify',
|
VERIFY_EMAIL = '/users/verify',
|
||||||
CHECK_CLOSED = '/auth/check-register',
|
SERVER_SETTINGS = '/server-settings',
|
||||||
UPDATE_SERVER_SETTINGS = '/admin/server-settings',
|
UPDATE_SERVER_SETTINGS = '/admin/server-settings',
|
||||||
INVITE_CODE = '/admin/invites',
|
INVITE_CODE = '/admin/invites',
|
||||||
}
|
}
|
||||||
|
@ -59,9 +59,7 @@ export const flameshotScript = (token: string) => `
|
||||||
IMAGEPATH="$HOME/Pictures/"
|
IMAGEPATH="$HOME/Pictures/"
|
||||||
IMAGENAME="$name-$(date +%s%N | sha256sum | base64 | head -c 32 ; echo)"
|
IMAGENAME="$name-$(date +%s%N | sha256sum | base64 | head -c 32 ; echo)"
|
||||||
KEY="${token}"
|
KEY="${token}"
|
||||||
DOMAIN="${serializeURL(
|
DOMAIN="${process.env.NEXT_PUBLIC_API_URL}/upload"
|
||||||
process.env.NEXT_PUBLIC_API_URL!
|
|
||||||
)}" # Your upload domain (without http:// or https://)
|
|
||||||
|
|
||||||
flameshot config -f "$IMAGENAME"
|
flameshot config -f "$IMAGENAME"
|
||||||
flameshot gui -r -p "$IMAGEPATH" > /dev/null
|
flameshot gui -r -p "$IMAGEPATH" > /dev/null
|
||||||
|
@ -76,28 +74,61 @@ if [ -f "$FILE" ]; then
|
||||||
-H "Accept: application/json" \
|
-H "Accept: application/json" \
|
||||||
-H "User-Agent: ShareX/13.4.0" \
|
-H "User-Agent: ShareX/13.4.0" \
|
||||||
-H "Authorization: $KEY" \
|
-H "Authorization: $KEY" \
|
||||||
-F "file=@$IMAGEPATH$IMAGENAME.png" "https://$DOMAIN/" | grep -Po '(?<="resource":")[^"]+')
|
-F "file=@$IMAGEPATH$IMAGENAME.png" "$DOMAIN" | grep -Po '(?<="resource":")[^"]+')
|
||||||
# printf instead of echo as echo appends a newline
|
|
||||||
printf "%s" "$URL" | xclip -sel clip
|
printf "%s" "$URL" | xclip -sel clip
|
||||||
rm "$IMAGEPATH$IMAGENAME.png" # Delete the image locally
|
rm "$IMAGEPATH$IMAGENAME.png"
|
||||||
else
|
else
|
||||||
echo "Aborted."
|
echo "Aborted."
|
||||||
fi
|
fi
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const MIME_TYPES = [
|
// export const MIME_TYPES = [
|
||||||
'image/png',
|
// 'image/png',
|
||||||
'image/gif',
|
// 'image/gif',
|
||||||
'image/jpeg',
|
// 'image/jpeg',
|
||||||
'image/svg+xml',
|
// 'image/svg+xml',
|
||||||
'image/webp',
|
// 'image/webp',
|
||||||
'audio/ogg',
|
// 'audio/ogg',
|
||||||
'audio/wave',
|
// 'audio/wave',
|
||||||
'audio/wav',
|
// 'audio/wav',
|
||||||
'audio/x-wav',
|
// 'audio/x-wav',
|
||||||
'audio/x-pn-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/mp3',
|
||||||
|
'audio/wav',
|
||||||
|
'audio/ogg',
|
||||||
|
'audio/flac',
|
||||||
|
'audio/aac',
|
||||||
|
'audio/m4a',
|
||||||
|
'audio/mp4',
|
||||||
'audio/mpeg',
|
'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/mp4',
|
||||||
'video/quicktime',
|
'video/quicktime',
|
||||||
'video/ogg',
|
'video/ogg',
|
||||||
|
@ -114,5 +145,13 @@ export const MIME_TYPES = [
|
||||||
'multipart/x-zip',
|
'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 =
|
export const CHUNK_SIZE =
|
||||||
+(process.env.NEXT_PUBLIC_CHUNK_SIZE ?? 10) * 1024 ** 2; // default: 10mb
|
+(process.env.NEXT_PUBLIC_CHUNK_SIZE ?? 10) * 1024 ** 2; // default: 10mb
|
||||||
|
|
|
@ -7,17 +7,19 @@ import axios from 'axios';
|
||||||
import { useForm } from '@mantine/form';
|
import { useForm } from '@mantine/form';
|
||||||
import { toErrorMap } from '@lib/utils';
|
import { toErrorMap } from '@lib/utils';
|
||||||
|
|
||||||
export const useSetServerSettings = (initialData: ServerSettings) => {
|
export const useSetServerSettings = (initialValues: ServerSettings) => {
|
||||||
const form = useForm<ServerSettings>({
|
const form = useForm<ServerSettings>({ initialValues });
|
||||||
initialValues: initialData,
|
|
||||||
});
|
|
||||||
const { data, mutate, isLoading, error } = useMutation(
|
const { data, mutate, isLoading, error } = useMutation(
|
||||||
['server-settings'],
|
['server-settings'],
|
||||||
(data: Partial<ServerSettings>) =>
|
(data: Partial<ServerSettings>) =>
|
||||||
axios
|
axios
|
||||||
.post(API_URL + API_ROUTES.UPDATE_SERVER_SETTINGS, data, {
|
.post<ServerSettings>(
|
||||||
withCredentials: true,
|
API_URL + API_ROUTES.UPDATE_SERVER_SETTINGS,
|
||||||
})
|
data,
|
||||||
|
{
|
||||||
|
withCredentials: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
updateNotification({
|
updateNotification({
|
||||||
id: 'server-settings',
|
id: 'server-settings',
|
||||||
|
@ -27,10 +29,7 @@ export const useSetServerSettings = (initialData: ServerSettings) => {
|
||||||
icon: <IconCheck />,
|
icon: <IconCheck />,
|
||||||
});
|
});
|
||||||
|
|
||||||
form.setValues({
|
form.setValues({ ...res.data });
|
||||||
INVITE_MODE: res.data.INVITE_MODE.toString(),
|
|
||||||
REGISTRATION_ENABLED: res.data.REGISTRATION_ENABLED.toString(),
|
|
||||||
});
|
|
||||||
|
|
||||||
return res.data;
|
return res.data;
|
||||||
})
|
})
|
||||||
|
|
|
@ -116,8 +116,8 @@ export interface EmbedSettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ServerSettings {
|
export interface ServerSettings {
|
||||||
REGISTRATION_ENABLED: string;
|
REGISTRATION_ENABLED: boolean;
|
||||||
INVITE_MODE: string;
|
INVITE_MODE: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Token = 'INVITE_CODE' | 'EMAIL_VERIFICATION';
|
type Token = 'INVITE_CODE' | 'EMAIL_VERIFICATION';
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { NotFoundTitle } from '@components/404Page';
|
import { NotFoundTitle } from '@pages/404Page';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const NotFound = () => {
|
const NotFound = () => {
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
import { ROUTES } from '@lib/constants';
|
|
||||||
import { useIsAuth } from '@lib/hooks';
|
|
||||||
import { CustomAppProps } from '@lib/types';
|
import { CustomAppProps } from '@lib/types';
|
||||||
import { MantineProvider } from '@mantine/core';
|
import { MantineProvider } from '@mantine/core';
|
||||||
import { NotificationsProvider } from '@mantine/notifications';
|
import { NotificationsProvider } from '@mantine/notifications';
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import { Suspense } from 'react';
|
const ProtectedWrapper = dynamic(() => import('@layouts/ProtectedWrapper'));
|
||||||
const LoadingPage = dynamic(() => import('@components/LoadingPage'));
|
|
||||||
const Layout = dynamic(() => import('@components/Layout'), { suspense: true });
|
|
||||||
|
|
||||||
export default function App({ Component, pageProps }: CustomAppProps) {
|
export default function App({ Component, pageProps }: CustomAppProps) {
|
||||||
const queryClient = new QueryClient();
|
const queryClient = new QueryClient();
|
||||||
|
@ -34,9 +30,9 @@ export default function App({ Component, pageProps }: CustomAppProps) {
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<NotificationsProvider>
|
<NotificationsProvider>
|
||||||
{Component.options?.auth ? (
|
{Component.options?.auth ? (
|
||||||
<Auth withLayout={Component.options.withLayout}>
|
<ProtectedWrapper withLayout={Component.options.withLayout}>
|
||||||
<Component {...pageProps} />
|
<Component {...pageProps} />
|
||||||
</Auth>
|
</ProtectedWrapper>
|
||||||
) : (
|
) : (
|
||||||
<Component {...pageProps} />
|
<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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
//! fix weird hydration issue
|
//! fix weird hydration issue
|
||||||
// TODO: find a better way to fix hydration issue
|
// TODO: find a better way to fix hydration issue
|
||||||
const SignInForm = dynamic(
|
const SignInForm = dynamic(
|
||||||
() => import('@components/Authentication').then((mod) => mod.SignInForm),
|
() => import('@components/pages/AuthPage').then((mod) => mod.SignInForm),
|
||||||
{ ssr: false }
|
{ ssr: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,47 +1,22 @@
|
||||||
import { SignUpForm } from '@components/Authentication';
|
import { SignUpPage } from '@pages/AuthPage';
|
||||||
import { API_ROUTES, API_URL, ROUTES } from '@lib/constants';
|
import { API_ROUTES, API_URL } from '@lib/constants';
|
||||||
import { ServerSettings } from '@lib/types';
|
import { ServerSettings } from '@lib/types';
|
||||||
import { Center, Tooltip, UnstyledButton } from '@mantine/core';
|
|
||||||
import { IconArrowBack } from '@tabler/icons';
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { InferGetServerSidePropsType, NextPage } from 'next';
|
import { InferGetServerSidePropsType, NextPage } from 'next';
|
||||||
import router from 'next/router';
|
|
||||||
|
|
||||||
const SignUp: NextPage<
|
const SignUp: NextPage<
|
||||||
InferGetServerSidePropsType<typeof getServerSideProps>
|
InferGetServerSidePropsType<typeof getServerSideProps>
|
||||||
> = (data) => {
|
> = (data) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Tooltip label="Home page">
|
<SignUpPage settings={data} />
|
||||||
<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>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getServerSideProps = async () => {
|
export const getServerSideProps = async () => {
|
||||||
const resp = await axios.get<ServerSettings>(
|
const resp = await axios.get<ServerSettings>(
|
||||||
API_URL + API_ROUTES.CHECK_CLOSED
|
API_URL + API_ROUTES.SERVER_SETTINGS
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
|
import InvitePage from '@components/pages/AdminPage/InvitePage';
|
||||||
import { API_ROUTES, API_URL, APP_NAME } from '@lib/constants';
|
import { API_ROUTES, API_URL, APP_NAME } from '@lib/constants';
|
||||||
import { useCreateInvite } from '@lib/hooks/useInviteCode';
|
|
||||||
import {
|
import {
|
||||||
CustomNextPage,
|
CustomNextPage,
|
||||||
Invite,
|
Invite,
|
||||||
ServerSettings,
|
ServerSettings,
|
||||||
SessionUser,
|
SessionUser,
|
||||||
} from '@lib/types';
|
} from '@lib/types';
|
||||||
import { Button, CopyButton, Group, PasswordInput, Stack } from '@mantine/core';
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { GetServerSidePropsContext } from 'next';
|
import { GetServerSidePropsContext } from 'next';
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
|
@ -14,39 +13,13 @@ import Head from 'next/head';
|
||||||
const AdminDash: CustomNextPage<ServerSettings & { invites: Invite[] }> = (
|
const AdminDash: CustomNextPage<ServerSettings & { invites: Invite[] }> = (
|
||||||
data
|
data
|
||||||
) => {
|
) => {
|
||||||
const { create, isLoading } = useCreateInvite();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
<title>{APP_NAME} | Admin</title>
|
<title>{APP_NAME} | Admin</title>
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
<Stack>
|
<InvitePage invites={data.invites} />
|
||||||
<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>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 { 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 axios from 'axios';
|
||||||
import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';
|
import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';
|
||||||
|
|
||||||
const Owner: CustomNextPage<
|
const Owner: CustomNextPage<
|
||||||
InferGetServerSidePropsType<typeof getServerSideProps>
|
InferGetServerSidePropsType<typeof getServerSideProps>
|
||||||
> = ({ data }) => {
|
> = ({ data }) => {
|
||||||
return <AdminForm {...data} />;
|
return <ServerPage {...data} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Owner;
|
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 {
|
return {
|
||||||
props: { data: serverData.data },
|
props: { data: serverData.data },
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import QuickActions from '@components/QuickActions';
|
import QuickActions from '@pages/DashboardPage';
|
||||||
import StatisticCard from '@components/StatisticCard';
|
import StatisticCard from '@layouts/StatisticCard';
|
||||||
import { API_ROUTES, API_URL, APP_NAME } from '@lib/constants';
|
import { API_ROUTES, API_URL, APP_NAME } from '@lib/constants';
|
||||||
import { CustomNextPage } from '@lib/types';
|
import { CustomNextPage } from '@lib/types';
|
||||||
import { Group } from '@mantine/core';
|
import { Group } from '@mantine/core';
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import UploadZone from '@components/Upload';
|
import UploadZone from '@pages/UploadPage';
|
||||||
import { APP_NAME } from '@lib/constants';
|
import { APP_NAME } from '@lib/constants';
|
||||||
import { CustomNextPage } from '@lib/types';
|
import { CustomNextPage } from '@lib/types';
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
|
|
|
@ -1,20 +1,15 @@
|
||||||
import Hero from '@components/Hero';
|
import HomePage from '@pages/HomePage';
|
||||||
import Navbar from '@components/Layout/Navbar';
|
|
||||||
import { API_ROUTES, API_URL } from '@lib/constants';
|
import { API_ROUTES, API_URL } from '@lib/constants';
|
||||||
import { SessionUser } from '@lib/types';
|
import { SessionUser } from '@lib/types';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';
|
import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';
|
||||||
import dynamic from 'next/dynamic';
|
|
||||||
const Sidebar = dynamic(() => import('@components/Layout/Sidebar'));
|
|
||||||
|
|
||||||
const Home = (
|
const Home = (
|
||||||
props: InferGetServerSidePropsType<typeof getServerSideProps>
|
props: InferGetServerSidePropsType<typeof getServerSideProps>
|
||||||
) => {
|
) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Navbar user={props?.user} />
|
<HomePage {...props} />
|
||||||
{props.user && <Sidebar />}
|
|
||||||
<Hero />
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import ProfilePage from '@components/ProfilePage';
|
import ProfilePage from '@pages/ProfilePage';
|
||||||
import { APP_NAME } from '@lib/constants';
|
import { APP_NAME } from '@lib/constants';
|
||||||
import { CustomNextPage } from '@lib/types';
|
import { CustomNextPage } from '@lib/types';
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import EmbedForm from '@components/Settings/EmbedForm';
|
import EmbedForm from '@pages/SettingPage/EmbedForm';
|
||||||
import EmbedPreview from '@components/Settings/EmbedPreview';
|
import EmbedPreview from '@pages/SettingPage/EmbedPreview';
|
||||||
import { API_URL, API_ROUTES } from '@lib/constants';
|
import { API_URL, API_ROUTES } from '@lib/constants';
|
||||||
import { useUpdateEmbedSettings } from '@lib/hooks';
|
import { useUpdateEmbedSettings } from '@lib/hooks';
|
||||||
import { CustomNextPage, EmbedSettings } from '@lib/types';
|
import { CustomNextPage, EmbedSettings } from '@lib/types';
|
||||||
|
|
|
@ -18,7 +18,8 @@
|
||||||
"paths": {
|
"paths": {
|
||||||
"@lib/*": ["lib/*"],
|
"@lib/*": ["lib/*"],
|
||||||
"@components/*": ["components/*"],
|
"@components/*": ["components/*"],
|
||||||
"@pages/*": ["pages/*"]
|
"@pages/*": ["components/pages/*"],
|
||||||
|
"@layouts/*": ["components/layouts/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "env.d.ts", "**/*.ts", "**/*.tsx"],
|
"include": ["next-env.d.ts", "env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||||
|
|
Loading…
Reference in New Issue