mirror of
https://github.com/DefectingCat/DefectingCat.github.io
synced 2025-07-15 16:51:37 +00:00
Add plant scale
* switch database to mysql * add find user api * add RUAInput compoent * update RUAButton onClick * refactor user api * add login form
This commit is contained in:
@ -39,7 +39,7 @@ export const menus: MenuItem[] = [
|
||||
{
|
||||
id: 5,
|
||||
name: 'Tweets',
|
||||
path: '/search',
|
||||
path: '/tweets',
|
||||
icon: FiTwitter,
|
||||
},
|
||||
{
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { FC } from 'react';
|
||||
import { FC, MouseEventHandler } from 'react';
|
||||
import cn from 'classnames';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
onClick?: MouseEventHandler<HTMLButtonElement> | undefined;
|
||||
}
|
||||
|
||||
const RUAButton: FC<Props> = ({ className, children }) => {
|
||||
const RUAButton: FC<Props> = ({ className, children, onClick }) => {
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
@ -15,6 +16,7 @@ const RUAButton: FC<Props> = ({ className, children }) => {
|
||||
'dark:text-gray-400 dark:bg-rua-gray-800 dark:active:bg-gray-600',
|
||||
className
|
||||
)}
|
||||
onClick={onClick}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
|
51
components/RUA/RUAInput.tsx
Normal file
51
components/RUA/RUAInput.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import {
|
||||
ChangeEventHandler,
|
||||
FC,
|
||||
HTMLInputTypeAttribute,
|
||||
KeyboardEventHandler,
|
||||
LegacyRef,
|
||||
} from 'react';
|
||||
import cn from 'classnames';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
ref?: LegacyRef<HTMLInputElement> | undefined;
|
||||
placeholder?: string;
|
||||
value?: string | number | readonly string[] | undefined;
|
||||
type?: HTMLInputTypeAttribute | undefined;
|
||||
onChange?: ChangeEventHandler<HTMLInputElement> | undefined;
|
||||
onKeyUp?: KeyboardEventHandler<HTMLInputElement> | undefined;
|
||||
}
|
||||
|
||||
const RUAInput: FC<Props> = ({
|
||||
className,
|
||||
ref,
|
||||
placeholder,
|
||||
value,
|
||||
onChange,
|
||||
onKeyUp,
|
||||
type,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<input
|
||||
ref={ref}
|
||||
type={type}
|
||||
placeholder={placeholder}
|
||||
className={cn(
|
||||
'rounded-lg outline-none relative',
|
||||
'py-4 px-4 placeholder:font-semibold',
|
||||
'focus:shadow-lg focus:placeholder:font-normal',
|
||||
'transition-all focus:z-20',
|
||||
'dark:bg-rua-gray-800',
|
||||
className
|
||||
)}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onKeyUp={onKeyUp}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default RUAInput;
|
@ -10,6 +10,9 @@ import cn from 'classnames';
|
||||
import { FiSearch } from 'react-icons/fi';
|
||||
import { useRouter } from 'next/router';
|
||||
import { ActionKind, useRUAContext } from 'lib/store';
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
const Input = dynamic(() => import('components/RUA/RUAInput'));
|
||||
|
||||
const SearchBox: FC = () => {
|
||||
// Add keyboard event to focus input element.
|
||||
@ -50,17 +53,11 @@ const SearchBox: FC = () => {
|
||||
)}
|
||||
/>
|
||||
|
||||
<input
|
||||
<Input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
className={cn(
|
||||
'w-full rounded-lg outline-none relative',
|
||||
'py-5 px-12 placeholder:font-semibold',
|
||||
'focus:px-5 focus:shadow-md focus:placeholder:font-normal',
|
||||
'transition-all focus:z-20',
|
||||
'dark:bg-rua-gray-800'
|
||||
)}
|
||||
className="!px-12 !py-5 focus:!px-5 w-full"
|
||||
value={state.searchQuery}
|
||||
onChange={handleInput}
|
||||
onKeyUp={handleSearch}
|
||||
|
46
pages/api/authenticate.ts
Normal file
46
pages/api/authenticate.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import 'dotenv/config';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const auth = async () => {
|
||||
const q = req.body;
|
||||
console.log(q);
|
||||
|
||||
// try {
|
||||
// const { name } = q;
|
||||
// if (Array.isArray(name)) throw new Error();
|
||||
|
||||
// const user = await prisma.users.findFirst({
|
||||
// select: {
|
||||
// username: true,
|
||||
// emil: true,
|
||||
// },
|
||||
// where: {
|
||||
// username: name,
|
||||
// },
|
||||
// });
|
||||
// user
|
||||
// ? res.status(200).json(user)
|
||||
// : res.status(404).json({
|
||||
// message: 'Not found.',
|
||||
// });
|
||||
// } catch (e) {
|
||||
// return res.status(404).json({
|
||||
// message: 'Not found.',
|
||||
// });
|
||||
// }
|
||||
};
|
||||
|
||||
switch (req.method) {
|
||||
case 'POST':
|
||||
return auth();
|
||||
default:
|
||||
return res.status(405).end(`Method ${req.method} Not Allowed`);
|
||||
}
|
||||
}
|
@ -1,25 +1,9 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { PrismaClient, Users } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const test = await prisma.users.findFirst({
|
||||
where: {
|
||||
username: 'test',
|
||||
},
|
||||
select: {
|
||||
username: true,
|
||||
Tweets: {
|
||||
select: {
|
||||
content: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
res.status(200).json(test);
|
||||
res.status(200).json({ hello: 'world' });
|
||||
}
|
||||
|
45
pages/api/user.ts
Normal file
45
pages/api/user.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import 'dotenv/config';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const findUser = async () => {
|
||||
const q = req.query;
|
||||
|
||||
try {
|
||||
const { name } = q;
|
||||
if (Array.isArray(name)) throw new Error();
|
||||
|
||||
const user = await prisma.users.findFirst({
|
||||
select: {
|
||||
username: true,
|
||||
emil: true,
|
||||
},
|
||||
where: {
|
||||
username: name,
|
||||
},
|
||||
});
|
||||
user
|
||||
? res.status(200).json(user)
|
||||
: res.status(404).json({
|
||||
message: 'Not found.',
|
||||
});
|
||||
} catch (e) {
|
||||
return res.status(404).json({
|
||||
message: 'Not found.',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
switch (req.method) {
|
||||
case 'GET':
|
||||
return findUser();
|
||||
default:
|
||||
return res.status(405).end(`Method ${req.method} Not Allowed`);
|
||||
}
|
||||
}
|
72
pages/tweets.tsx
Normal file
72
pages/tweets.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import { ReactElement, useState } from 'react';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { InferGetStaticPropsType } from 'next';
|
||||
import Head from 'next/head';
|
||||
import cn from 'classnames';
|
||||
|
||||
const MainLayout = dynamic(() => import('layouts/MainLayout'));
|
||||
const Button = dynamic(() => import('components/RUA/RUAButton'));
|
||||
const Input = dynamic(() => import('components/RUA/RUAInput'));
|
||||
|
||||
const Tweets = ({ tweets }: InferGetStaticPropsType<typeof getStaticProps>) => {
|
||||
const [showInput, setShowInput] = useState(false);
|
||||
const [showOverFlow, setShowOverFlow] = useState(true);
|
||||
const handleLoginClick = () => {
|
||||
if (!showInput) {
|
||||
setShowInput(true);
|
||||
setTimeout(() => {
|
||||
setShowOverFlow(false);
|
||||
}, 299);
|
||||
} else {
|
||||
// handle login
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>RUA - Tweets</title>
|
||||
</Head>
|
||||
|
||||
<div>
|
||||
<div className={cn('')}>
|
||||
<div
|
||||
className={cn(
|
||||
'flex flex-col mb-4',
|
||||
'text-sm md:w-1/2 transition-all',
|
||||
'max-h-0 duration-300',
|
||||
{ 'overflow-hidden': showOverFlow },
|
||||
{ 'max-h-32': showInput }
|
||||
)}
|
||||
>
|
||||
<Input placeholder="Username" className="py-3 mb-4" />
|
||||
<Input placeholder="Password" className="py-3" type="password" />
|
||||
</div>
|
||||
<Button className="px-5 py-2" onClick={handleLoginClick}>
|
||||
Login{showInput ? '!' : '?'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Tweets.getLayout = function getLayout(page: ReactElement) {
|
||||
return <MainLayout>{page}</MainLayout>;
|
||||
};
|
||||
|
||||
export default Tweets;
|
||||
|
||||
export const getStaticProps = async () => {
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
const tweets = await prisma.tweets.findMany();
|
||||
|
||||
return {
|
||||
props: {
|
||||
tweets,
|
||||
},
|
||||
revalidate: 10,
|
||||
};
|
||||
};
|
@ -2,12 +2,14 @@
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
provider = "prisma-client-js"
|
||||
previewFeatures = ["referentialIntegrity"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
provider = "mysql"
|
||||
url = env("DATABASE_URL")
|
||||
referentialIntegrity = "prisma"
|
||||
}
|
||||
|
||||
model Users {
|
||||
|
Reference in New Issue
Block a user