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:
DefectingCat
2022-01-28 16:42:59 +08:00
parent 30c4540594
commit 5c6f91fed6
9 changed files with 230 additions and 31 deletions

View File

@ -39,7 +39,7 @@ export const menus: MenuItem[] = [
{
id: 5,
name: 'Tweets',
path: '/search',
path: '/tweets',
icon: FiTwitter,
},
{

View File

@ -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>

View 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;

View File

@ -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
View 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`);
}
}

View File

@ -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
View 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
View 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,
};
};

View File

@ -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 {