mirror of
https://github.com/fergalmoran/opengifame.git
synced 2025-12-22 09:38:44 +00:00
Fix register page
This commit is contained in:
@@ -1,90 +0,0 @@
|
||||
import React from 'react';
|
||||
import { SessionProvider } from 'next-auth/react';
|
||||
import { Session } from 'next-auth';
|
||||
import '@styles/globals.css';
|
||||
import type { AppProps } from 'next/app';
|
||||
import { PageLayout } from 'components/layout';
|
||||
import { generateBrowserId } from '@lib/browser';
|
||||
import Cookies from 'js-cookie';
|
||||
import Head from 'next/head';
|
||||
import { NextPageWithLayout } from 'types/page-with-layout';
|
||||
import { ThemeProvider } from 'next-themes';
|
||||
|
||||
type AppPropsWithLayout<T> = AppProps<T> & {
|
||||
Component: NextPageWithLayout;
|
||||
};
|
||||
|
||||
const MyApp = ({
|
||||
Component,
|
||||
pageProps: { session, ...pageProps },
|
||||
}: AppPropsWithLayout<{ session: Session }>) => {
|
||||
const getLayout =
|
||||
Component.getLayout ??
|
||||
((page: React.ReactElement) => (
|
||||
<ThemeProvider
|
||||
defaultTheme="luxury"
|
||||
storageKey="__theme"
|
||||
>
|
||||
<PageLayout>
|
||||
<Component {...pageProps} />
|
||||
</PageLayout>
|
||||
</ThemeProvider>
|
||||
));
|
||||
React.useEffect(() => {
|
||||
const checkBrowserId = async () => {
|
||||
const storedId = localStorage.getItem('__effp');
|
||||
if (!storedId) {
|
||||
localStorage.setItem('__effp', generateBrowserId());
|
||||
}
|
||||
Cookies.set('bid', localStorage.getItem('__effp') as string, {
|
||||
sameSite: 'strict',
|
||||
expires: new Date(8640000000000000),
|
||||
});
|
||||
};
|
||||
checkBrowserId().catch(console.error);
|
||||
}, []);
|
||||
return (
|
||||
<SessionProvider session={session}>
|
||||
<Head>
|
||||
<title>Frasier Gifs</title>
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
href="/apple-touch-icon.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="32x32"
|
||||
href="/favicon-32x32.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="16x16"
|
||||
href="/favicon-16x16.png"
|
||||
/>
|
||||
<link
|
||||
rel="manifest"
|
||||
href="/site.webmanifest"
|
||||
/>
|
||||
<link
|
||||
rel="mask-icon"
|
||||
href="/safari-pinned-tab.svg"
|
||||
color="#5bbad5"
|
||||
/>
|
||||
<meta
|
||||
name="msapplication-TileColor"
|
||||
content="#da532c"
|
||||
/>
|
||||
<meta
|
||||
name="theme-color"
|
||||
content="#ffffff"
|
||||
/>
|
||||
</Head>
|
||||
{getLayout(<Component {...pageProps} />)}
|
||||
</SessionProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default MyApp;
|
||||
@@ -1,220 +0,0 @@
|
||||
import React, { FormEventHandler } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { logger } from '@lib/logger';
|
||||
|
||||
const SignUpPage = () => {
|
||||
const router = useRouter();
|
||||
const [userInfo, setUserInfo] = React.useState({
|
||||
email: 'fergal.moran+frasiergifs@gmail.com',
|
||||
password: 'secret',
|
||||
repeatPassword: 'secret',
|
||||
});
|
||||
const handleSubmit: FormEventHandler<HTMLFormElement> = async (e) => {
|
||||
//TODO: validation
|
||||
e.preventDefault();
|
||||
try {
|
||||
const res = await fetch(`/api/user/create`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
email: userInfo.email,
|
||||
password: userInfo.password,
|
||||
}),
|
||||
});
|
||||
logger.debug(`res`, res);
|
||||
router.push(
|
||||
`signin${
|
||||
router.query.callbackUrl
|
||||
? `?callbackUrl=${router.query.callbackUrl}`
|
||||
: ''
|
||||
}`
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col justify-center min-h-full py-12 sm:px-6 lg:px-8">
|
||||
<div className="sm:mx-auto sm:w-full sm:max-w-md">
|
||||
{/* <Image alt="Signin"
|
||||
height="128"
|
||||
width="128"
|
||||
className="w-auto h-16 mx-auto rounded-full"
|
||||
src={`/img/sign-in.gif`} /> */}
|
||||
<img
|
||||
className="w-auto h-32 mx-auto rounded-full"
|
||||
src={`/img/sign-in.gif`}
|
||||
alt="Workflow"
|
||||
/>
|
||||
<h2 className="mt-2 text-3xl font-extrabold text-center text-gray-800">
|
||||
Create new account
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<div className="px-4 py-8 bg-white shadow sm:rounded-lg sm:px-10">
|
||||
<form
|
||||
className="space-y-6"
|
||||
onSubmit={handleSubmit}
|
||||
method="post"
|
||||
>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="email"
|
||||
className="block text-sm font-medium text-gray-700"
|
||||
>
|
||||
{' '}
|
||||
Email address{' '}
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
autoComplete="email"
|
||||
required
|
||||
value={userInfo.email}
|
||||
onChange={({ target }) =>
|
||||
setUserInfo({ ...userInfo, email: target.value })
|
||||
}
|
||||
className="block w-full px-3 py-2 placeholder-gray-400 border border-gray-300 rounded-md shadow-sm appearance-none focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="password"
|
||||
className="block text-sm font-medium text-gray-700"
|
||||
>
|
||||
{' '}
|
||||
Password{' '}
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<input
|
||||
id="password"
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
required
|
||||
value={userInfo.password}
|
||||
onChange={({ target }) =>
|
||||
setUserInfo({ ...userInfo, password: target.value })
|
||||
}
|
||||
className="block w-full px-3 py-2 placeholder-gray-400 border border-gray-300 rounded-md shadow-sm appearance-none focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="repeat-password"
|
||||
className="block text-sm font-medium text-gray-700"
|
||||
>
|
||||
{' '}
|
||||
Repeat password{' '}
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<input
|
||||
id="repeat-password"
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
required
|
||||
value={userInfo.repeatPassword}
|
||||
onChange={({ target }) =>
|
||||
setUserInfo({ ...userInfo, repeatPassword: target.value })
|
||||
}
|
||||
className="block w-full px-3 py-2 placeholder-gray-400 border border-gray-300 rounded-md shadow-sm appearance-none focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
type="submit"
|
||||
className="flex justify-center w-full px-4 py-2 text-sm font-medium text-white bg-indigo-600 border border-transparent rounded-md shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
>
|
||||
Create account
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div className="mt-6">
|
||||
<div className="relative">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<div className="w-full border-t border-gray-300" />
|
||||
</div>
|
||||
<div className="relative flex justify-center text-sm">
|
||||
<span className="px-2 text-gray-500 bg-white">
|
||||
{' '}
|
||||
Or continue with{' '}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-3 gap-3 mt-6">
|
||||
<div>
|
||||
<a
|
||||
href="#"
|
||||
className="inline-flex justify-center w-full px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-md shadow-sm hover:bg-gray-50"
|
||||
>
|
||||
<span className="sr-only">Sign in with Facebook</span>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M20 10c0-5.523-4.477-10-10-10S0 4.477 0 10c0 4.991 3.657 9.128 8.438 9.878v-6.987h-2.54V10h2.54V7.797c0-2.506 1.492-3.89 3.777-3.89 1.094 0 2.238.195 2.238.195v2.46h-1.26c-1.243 0-1.63.771-1.63 1.562V10h2.773l-.443 2.89h-2.33v6.988C16.343 19.128 20 14.991 20 10z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a
|
||||
href="#"
|
||||
className="inline-flex justify-center w-full px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-md shadow-sm hover:bg-gray-50"
|
||||
>
|
||||
<span className="sr-only">Sign in with Twitter</span>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M6.29 18.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0020 3.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.073 4.073 0 01.8 7.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 010 16.407a11.616 11.616 0 006.29 1.84" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a
|
||||
href="#"
|
||||
className="inline-flex justify-center w-full px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-md shadow-sm hover:bg-gray-50"
|
||||
>
|
||||
<span className="sr-only">Sign in with GitHub</span>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M10 0C4.477 0 0 4.484 0 10.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0110 4.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.203 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.942.359.31.678.921.678 1.856 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0020 10.017C20 4.484 15.522 0 10 0z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SignUpPage;
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
const ColoursPage = () => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="inline-flex space-x-5">
|
||||
<button className="px-4 py-2 font-bold text-gray-800 py-2rounded bg-tofu">
|
||||
Tofu
|
||||
</button>
|
||||
<button className="px-4 py-2 font-bold text-gray-800 rounded bg-putty">
|
||||
Putty
|
||||
</button>
|
||||
<button className="px-4 py-2 font-bold text-gray-800 rounded bg-oatmeal">
|
||||
Oatmeal
|
||||
</button>
|
||||
<button className="px-4 py-2 font-bold text-gray-800 rounded bg-almond">
|
||||
Almond
|
||||
</button>
|
||||
<button className="px-4 py-2 font-bold text-gray-800 rounded bg-harvestwheat">
|
||||
Harvest Wheat
|
||||
</button>
|
||||
<button className="px-4 py-2 font-bold text-gray-800 rounded bg-buff">
|
||||
And Buff
|
||||
</button>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
export default ColoursPage;
|
||||
@@ -1,56 +0,0 @@
|
||||
import { NextPage, GetServerSideProps } from 'next';
|
||||
import { useSession } from 'next-auth/react';
|
||||
import Router from 'next/router';
|
||||
import React from 'react';
|
||||
import SharingEmbedComponent from '@components/sharing/SharingEmbedComponent';
|
||||
import { Gif } from 'models';
|
||||
import { mapGif } from '@lib/mapping/gif';
|
||||
import client from '@lib/prismadb';
|
||||
interface IDebugPageProps {
|
||||
gif: Gif;
|
||||
}
|
||||
const DebugPage: NextPage<IDebugPageProps> = ({ gif }): JSX.Element => {
|
||||
const { status, data } = useSession();
|
||||
React.useEffect(() => {
|
||||
if (status === 'unauthenticated') Router.replace('/auth/signin');
|
||||
}, [status]);
|
||||
|
||||
if (status === 'authenticated') {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<SharingEmbedComponent
|
||||
onClose={() => close()}
|
||||
gif={gif}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
return <div>Loading....</div>;
|
||||
};
|
||||
export const getServerSideProps: GetServerSideProps = async ({ req }) => {
|
||||
const results = await client.gif.findMany({
|
||||
take: 1,
|
||||
include: {
|
||||
_count: {
|
||||
select: {
|
||||
upVotes: true,
|
||||
downVotes: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: {
|
||||
upVotes: {
|
||||
_count: 'desc',
|
||||
},
|
||||
},
|
||||
});
|
||||
const gifs = await Promise.all(
|
||||
results.map(async (gif): Promise<Gif> => mapGif(gif))
|
||||
);
|
||||
return {
|
||||
props: {
|
||||
gif: gifs[0],
|
||||
},
|
||||
};
|
||||
};
|
||||
export default DebugPage;
|
||||
@@ -1,78 +0,0 @@
|
||||
import {
|
||||
AddCommentComponent,
|
||||
GifContainer,
|
||||
SharingComponent,
|
||||
} from '@components';
|
||||
import React from 'react';
|
||||
import { GetServerSideProps } from 'next';
|
||||
import client from '@lib/prismadb';
|
||||
import { Gif } from 'models';
|
||||
import { mapGif } from '@lib/mapping/gif';
|
||||
interface IGifPageProps {
|
||||
gif: Gif;
|
||||
}
|
||||
const GifPage: React.FC<IGifPageProps> = ({ gif }) => {
|
||||
return (
|
||||
<div className="relative overflow-hidden">
|
||||
<div className="relative pb-16 sm:pb-24 lg:pb-32">
|
||||
<main className="px-4 mx-auto max-w-7xl sm:px-6">
|
||||
<div className="lg:grid lg:grid-cols-12 lg:gap-8">
|
||||
<div className="sm:text-center md:max-w-2xl lg:col-span-6 lg:text-left">
|
||||
<h1>
|
||||
<span className="block mt-1 text-4xl font-extrabold tracking-tight sm:text-5xl xl:text-6xl">
|
||||
<span className="block text-accent">{gif.title}</span>
|
||||
</span>
|
||||
</h1>
|
||||
<p className="mt-3 text-base sm:mt-5 sm:text-xl lg:text-lg xl:text-xl">
|
||||
{gif.description}
|
||||
</p>
|
||||
<SharingComponent gif={gif} />
|
||||
{/* <div className="mt-5">
|
||||
<AddCommentComponent />
|
||||
</div> */}
|
||||
</div>
|
||||
<div className="relative mt-12 sm:max-w-lg sm:mx-auto lg:mt-0 lg:max-w-none lg:mx-0 lg:col-span-6 lg:flex lg:items-center">
|
||||
<div className="relative w-full mx-auto rounded-lg shadow-lg lg:max-w-md">
|
||||
<span className="sr-only">The gif</span>
|
||||
<GifContainer
|
||||
gif={gif}
|
||||
isLink={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async ({
|
||||
params,
|
||||
req,
|
||||
}) => {
|
||||
const gif = await client.gif.findUnique({
|
||||
where: {
|
||||
slug: params?.slug as string,
|
||||
},
|
||||
include: {
|
||||
_count: {
|
||||
select: {
|
||||
upVotes: true,
|
||||
downVotes: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!gif) {
|
||||
return {
|
||||
notFound: true,
|
||||
};
|
||||
}
|
||||
return {
|
||||
props: {
|
||||
gif: mapGif(gif),
|
||||
},
|
||||
};
|
||||
};
|
||||
export default GifPage;
|
||||
@@ -1,56 +0,0 @@
|
||||
import type { GetServerSideProps, NextPage } from 'next';
|
||||
import { Gif } from 'models';
|
||||
import { GifContainer } from 'components';
|
||||
import { mapGif } from '@lib/mapping/gif';
|
||||
import client from '@lib/prismadb';
|
||||
|
||||
interface IHomeProps {
|
||||
gifs: Gif[];
|
||||
}
|
||||
|
||||
const Home: NextPage<IHomeProps> = ({ gifs }) => {
|
||||
return (
|
||||
<div>
|
||||
<div className="grid grid-cols-1 xl:grid-cols-4 lg:grid-cols-3 md:grid-cols-2">
|
||||
{gifs.map((gif: Gif) => {
|
||||
return (
|
||||
<div
|
||||
key={gif.id}
|
||||
className="m-2"
|
||||
>
|
||||
<GifContainer gif={gif} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async ({ req }) => {
|
||||
const results = await client.gif.findMany({
|
||||
take: 12,
|
||||
include: {
|
||||
_count: {
|
||||
select: {
|
||||
upVotes: true,
|
||||
downVotes: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: {
|
||||
upVotes: {
|
||||
_count: 'desc',
|
||||
},
|
||||
},
|
||||
});
|
||||
const gifs = await Promise.all(
|
||||
results.map(async (gif): Promise<Gif> => mapGif(gif))
|
||||
);
|
||||
return {
|
||||
props: {
|
||||
gifs,
|
||||
},
|
||||
};
|
||||
};
|
||||
export default Home;
|
||||
@@ -1,18 +0,0 @@
|
||||
import { NextPage } from 'next';
|
||||
import { useSession } from 'next-auth/react';
|
||||
import Router from 'next/router';
|
||||
import React from 'react';
|
||||
|
||||
const ProtectedPage: NextPage = (): JSX.Element => {
|
||||
const { status, data } = useSession();
|
||||
React.useEffect(() => {
|
||||
if (status === 'unauthenticated') Router.replace('/auth/signin');
|
||||
}, [status]);
|
||||
|
||||
if (status === 'authenticated') {
|
||||
return <div>ProtectedPage</div>;
|
||||
}
|
||||
return <div>Loading....</div>;
|
||||
};
|
||||
|
||||
export default ProtectedPage;
|
||||
@@ -1,34 +0,0 @@
|
||||
import React from 'react';
|
||||
import { useSession } from 'next-auth/react';
|
||||
import Router from 'next/router';
|
||||
|
||||
const RequestPage = () => {
|
||||
const { status } = useSession();
|
||||
React.useEffect(() => {
|
||||
if (status === 'unauthenticated') Router.replace('/auth/signin');
|
||||
}, [status]);
|
||||
|
||||
return status === 'authenticated' ? (
|
||||
<div className="relative px-4 sm:px-6 lg:px-8">
|
||||
<div className="mx-auto text-lg max-w-prose">
|
||||
<h1>
|
||||
<span className="block text-base font-semibold tracking-wide text-center uppercase">
|
||||
Work in progress
|
||||
</span>
|
||||
<span className="block mt-2 text-3xl font-extrabold leading-8 tracking-tight text-center sm:text-4xl">
|
||||
Request a gif
|
||||
</span>
|
||||
</h1>
|
||||
<p className="mt-8 text-xl leading-8">
|
||||
Here you can allow your users to request a gif, if you have the TV
|
||||
Show module enabled you can allow Season/Episode/Timestamp/Duration
|
||||
type stuff
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div>Loading....</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RequestPage;
|
||||
@@ -1,57 +0,0 @@
|
||||
import React from 'react';
|
||||
import { ThemeProvider } from 'next-themes';
|
||||
import { NextPageWithLayout } from 'types/page-with-layout';
|
||||
import { Gif } from '@models';
|
||||
import { GetServerSideProps } from 'next';
|
||||
import { mapGif } from '@lib/mapping/gif';
|
||||
import client from '@lib/prismadb';
|
||||
import { GifContainer } from '@components';
|
||||
|
||||
interface IShareGifPageProps {
|
||||
gif: Gif;
|
||||
}
|
||||
const ShareGifPage: NextPageWithLayout<IShareGifPageProps> = ({ gif }) => {
|
||||
return (
|
||||
<div className="p-2 w-96">
|
||||
<GifContainer
|
||||
gif={gif}
|
||||
isLink={true}
|
||||
showDetails={false}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
ShareGifPage.getLayout = (page: React.ReactElement) => {
|
||||
return <ThemeProvider defaultTheme="light">{page}</ThemeProvider>;
|
||||
};
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async ({
|
||||
params,
|
||||
req,
|
||||
}) => {
|
||||
const gif = await client.gif.findUnique({
|
||||
where: {
|
||||
slug: params?.gif as string,
|
||||
},
|
||||
include: {
|
||||
_count: {
|
||||
select: {
|
||||
upVotes: true,
|
||||
downVotes: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!gif) {
|
||||
return {
|
||||
notFound: true,
|
||||
};
|
||||
}
|
||||
return {
|
||||
props: {
|
||||
gif: mapGif(gif),
|
||||
},
|
||||
};
|
||||
};
|
||||
export default ShareGifPage;
|
||||
@@ -1,224 +0,0 @@
|
||||
import React from 'react';
|
||||
import { GetServerSideProps, NextPage } from 'next';
|
||||
import { Season, Episode } from 'models';
|
||||
import prisma from '@lib/prismadb';
|
||||
import { ImageUpload, TaggedInput } from '@components';
|
||||
import { Controller, SubmitHandler, useForm } from 'react-hook-form';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useSession } from 'next-auth/react';
|
||||
import Router from 'next/router';
|
||||
|
||||
interface IUploadProps {
|
||||
seasons: Season[];
|
||||
}
|
||||
|
||||
const UploadPage: NextPage<IUploadProps> = ({ seasons }) => {
|
||||
const { status } = useSession();
|
||||
React.useEffect(() => {
|
||||
if (status === 'unauthenticated') Router.replace('/auth/signin');
|
||||
}, [status]);
|
||||
|
||||
type FormValues = {
|
||||
title: string;
|
||||
description: string;
|
||||
terms: string[];
|
||||
image: string | undefined;
|
||||
};
|
||||
const {
|
||||
register,
|
||||
control,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
} = useForm<FormValues>({
|
||||
defaultValues: {
|
||||
title: 'argle',
|
||||
description: 'Argle bargle Foo Ferra',
|
||||
terms: ['Niles', 'Frasier'],
|
||||
image: undefined,
|
||||
},
|
||||
});
|
||||
const router = useRouter();
|
||||
const [seasonEpisodes, setSeasonEpisodes] = React.useState<Array<Episode>>(
|
||||
[]
|
||||
);
|
||||
const [currentSeason, setCurrentSeason] = React.useState<Season>(seasons[0]);
|
||||
React.useEffect(() => {
|
||||
setSeasonEpisodes(currentSeason.episodes);
|
||||
}, [currentSeason]);
|
||||
const onSubmit: SubmitHandler<FormValues> = async (data) => {
|
||||
console.log(data);
|
||||
if (data.image) {
|
||||
const body = new FormData();
|
||||
body.append('title', data.title);
|
||||
body.append('description', data.description);
|
||||
body.append('terms', data.terms.join('|'));
|
||||
body.append('file', data.image);
|
||||
const response = await fetch('api/upload', {
|
||||
method: 'POST',
|
||||
body,
|
||||
});
|
||||
if (response.status === 201) {
|
||||
await router.replace('/');
|
||||
}
|
||||
}
|
||||
};
|
||||
return status === 'authenticated' ? (
|
||||
<div className="md:grid md:grid-cols-3 md:gap-6">
|
||||
<div className="md:col-span-1">
|
||||
<div className="px-4 sm:px-0">
|
||||
<h3 className="text-lg font-extrabold leading-6">Upload a new gif</h3>
|
||||
<p className="my-3 text-sm text-base-content/70">
|
||||
The more info you can give us the better.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="md:col-span-2">
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="shadow sm:rounded-md sm:overflow-hidden">
|
||||
<div className="px-4 space-y-4">
|
||||
<div className="col-span-3 sm:col-span-2">
|
||||
<label
|
||||
htmlFor="title"
|
||||
className="block text-sm font-medium"
|
||||
>
|
||||
Title
|
||||
</label>
|
||||
<div className="flex mt-1 rounded-md shadow-sm">
|
||||
<input
|
||||
{...register('title', { required: 'Title is required' })}
|
||||
type="text"
|
||||
name="title"
|
||||
className="flex-1 block w-full rounded-md input input-bordered rounded-r-md sm:text-sm"
|
||||
placeholder="Title for this gif"
|
||||
/>
|
||||
</div>
|
||||
<p className="mt-2 text-sm text-red-600">
|
||||
{errors.title?.message}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="description"
|
||||
className="block text-sm font-medium"
|
||||
>
|
||||
Description
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<textarea
|
||||
{...register('description', {
|
||||
required: 'Description is required',
|
||||
})}
|
||||
name="description"
|
||||
rows={3}
|
||||
className="block w-full mt-1 border rounded-md shadow-sm textarea textarea-bordered sm:text-sm"
|
||||
placeholder="Description for this gif"
|
||||
/>
|
||||
</div>
|
||||
<p className="mt-2 text-sm text-red-600">
|
||||
{errors.description?.message}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium">The gif</label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="image"
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<ImageUpload
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="pt-4 divider">optional stuff</div>
|
||||
<Controller
|
||||
control={control}
|
||||
name="terms"
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<TaggedInput
|
||||
label="Search terms"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<div className="grid grid-cols-3 gap-6">
|
||||
<div className="col-span-1">
|
||||
<label
|
||||
className="label"
|
||||
htmlFor="season"
|
||||
>
|
||||
<span className="label-text">Season</span>
|
||||
</label>
|
||||
<select
|
||||
onChange={($event) =>
|
||||
setCurrentSeason(
|
||||
seasons.filter(
|
||||
(f) => f.number === Number($event.currentTarget.value)
|
||||
)[0]
|
||||
)
|
||||
}
|
||||
id="season"
|
||||
className="w-full max-w-xs select select-bordered"
|
||||
>
|
||||
{seasons.map((s) => (
|
||||
<option key={s.id}>{s.number}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<label
|
||||
className="label"
|
||||
htmlFor="episode"
|
||||
>
|
||||
<span className="label-text">Episode</span>
|
||||
</label>
|
||||
<select
|
||||
id="episode"
|
||||
className="w-full select select-bordered"
|
||||
>
|
||||
{seasonEpisodes.map((s) => (
|
||||
<option key={s.id}>{s.name}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-full px-4 py-3 text-right ">
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full btn btn-primary"
|
||||
>
|
||||
Upload Gif
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div>Loading....</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async ({ req }) => {
|
||||
const seasons = await prisma.season.findMany({
|
||||
include: {
|
||||
episodes: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
seasonId: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
return {
|
||||
props: {
|
||||
seasons,
|
||||
},
|
||||
};
|
||||
};
|
||||
export default UploadPage;
|
||||
@@ -8,8 +8,8 @@ import { signIn } from 'next-auth/react';
|
||||
const SignInPage = () => {
|
||||
const router = useRouter();
|
||||
const [userInfo, setUserInfo] = React.useState({
|
||||
email: 'fergal.moran+frasiergifs@gmail.com',
|
||||
password: 'secret',
|
||||
email: '',
|
||||
password: '',
|
||||
});
|
||||
const handleSubmit: FormEventHandler<HTMLFormElement> = async (e) => {
|
||||
//TODO: validation
|
||||
|
||||
@@ -1,48 +1,51 @@
|
||||
import { signIn } from 'next-auth/react';
|
||||
'use client';
|
||||
|
||||
import React, { FormEventHandler } from 'react';
|
||||
import Router from 'next/router';
|
||||
import Image from "next/image";
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
import { logger } from '@lib/logger';
|
||||
import { debug } from 'console';
|
||||
import { SocialLogin } from '@components';
|
||||
const SigninPage = () => {
|
||||
|
||||
const SignUpPage = () => {
|
||||
const router = useRouter();
|
||||
const [userInfo, setUserInfo] = React.useState({
|
||||
email: 'fergal.moran+frasiergifs@gmail.com',
|
||||
password: 'secret',
|
||||
email: '',
|
||||
password: '',
|
||||
repeatPassword: '',
|
||||
});
|
||||
const handleSubmit: FormEventHandler<HTMLFormElement> = async (e) => {
|
||||
//TODO: validation
|
||||
e.preventDefault();
|
||||
const res = await signIn('credentials', {
|
||||
try {
|
||||
const res = await fetch(`/api/user/create`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
email: userInfo.email,
|
||||
password: userInfo.password,
|
||||
redirect: false,
|
||||
}),
|
||||
});
|
||||
if (res?.status === 200) {
|
||||
Router.replace('/');
|
||||
logger.debug(`res`, res);
|
||||
router.push(
|
||||
`signin${
|
||||
router.query.callbackUrl
|
||||
? `?callbackUrl=${router.query.callbackUrl}`
|
||||
: ''
|
||||
}`
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
console.log('signin', 'handleSubmit', res);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col justify-center min-h-full py-1 sm:px-6 lg:px-8">
|
||||
<div className="flex flex-col justify-center min-h-full py-12 sm:px-6 lg:px-8">
|
||||
<div className="sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<h2 className="mt-2 text-3xl font-extrabold text-center ">
|
||||
Sign in to your account
|
||||
Create new account
|
||||
</h2>
|
||||
<p className="mt-2 text-sm text-center ">
|
||||
Or{' '}
|
||||
<Link
|
||||
href="/auth/signup"
|
||||
className="font-medium "
|
||||
>
|
||||
create a new account
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-2 sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<div className="px-4 py-8 shadow sm:rounded-lg sm:px-10">
|
||||
<form
|
||||
className="space-y-6"
|
||||
@@ -54,7 +57,8 @@ const SigninPage = () => {
|
||||
htmlFor="email"
|
||||
className="block text-sm font-medium "
|
||||
>
|
||||
Email address
|
||||
{' '}
|
||||
Email address{' '}
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<input
|
||||
@@ -76,7 +80,8 @@ const SigninPage = () => {
|
||||
htmlFor="password"
|
||||
className="block text-sm font-medium"
|
||||
>
|
||||
Password
|
||||
{' '}
|
||||
Password{' '}
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<input
|
||||
@@ -92,30 +97,25 @@ const SigninPage = () => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center">
|
||||
<input
|
||||
id="remember-me"
|
||||
name="remember-me"
|
||||
type="checkbox"
|
||||
className="w-4 h-4"
|
||||
/>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="remember-me"
|
||||
className="block ml-2 text-sm text-accent"
|
||||
htmlFor="repeat-password"
|
||||
className="block text-sm font-medium"
|
||||
>
|
||||
Remember me
|
||||
Repeat password
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="text-sm">
|
||||
<a
|
||||
href="#"
|
||||
className="font-medium text-info hover:text-primary/50"
|
||||
>
|
||||
Forgot your password?
|
||||
</a>
|
||||
<div className="mt-1">
|
||||
<input
|
||||
id="repeat-password"
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
required
|
||||
value={userInfo.repeatPassword}
|
||||
onChange={({ target }) =>
|
||||
setUserInfo({ ...userInfo, repeatPassword: target.value })
|
||||
}
|
||||
className="w-full input input-bordered"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -124,7 +124,7 @@ const SigninPage = () => {
|
||||
type="submit"
|
||||
className="w-full btn btn-primary"
|
||||
>
|
||||
Sign in
|
||||
Create account
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -138,4 +138,4 @@ const SigninPage = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default SigninPage;
|
||||
export default SignUpPage;
|
||||
@@ -36,7 +36,7 @@
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts"
|
||||
, ".pages/upload.tsx" ],
|
||||
, ".working/.pages/upload.tsx" ],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user