-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* fix up login flow * nav buttons * headers + listings
- Loading branch information
1 parent
0ecd9ed
commit 1925e95
Showing
23 changed files
with
483 additions
and
579 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import BackButton from "components/ui/Button/BackButton"; | ||
import { Card, CardContent, CardFooter, CardHeader } from "components/ui/Card"; | ||
import Header from "components/ui/Header"; | ||
import { useAlertQueue } from "hooks/alerts"; | ||
import { useAuthentication } from "hooks/auth"; | ||
import { useEffect, useState } from "react"; | ||
import { Spinner } from "react-bootstrap"; | ||
import AuthProvider from "./AuthProvider"; | ||
import LoginForm from "./LoginForm"; | ||
import SignupForm from "./SignupForm"; | ||
|
||
export const AuthBlockInner = () => { | ||
const auth = useAuthentication(); | ||
const { addErrorAlert } = useAlertQueue(); | ||
|
||
const [isSignup, setIsSignup] = useState(false); | ||
const [useSpinner, setUseSpinner] = useState(false); | ||
|
||
const handleGithubSubmit = async ( | ||
event: React.MouseEvent<HTMLButtonElement>, | ||
) => { | ||
event.preventDefault(); | ||
|
||
const { data, error } = await auth.client.GET("/users/github/login"); | ||
if (error) { | ||
addErrorAlert(error); | ||
} else { | ||
window.open(data, "_self"); | ||
} | ||
}; | ||
|
||
useEffect(() => { | ||
(async () => { | ||
// Get the code from the query string to carry out OAuth login. | ||
const search = window.location.search; | ||
const params = new URLSearchParams(search); | ||
const code = params.get("code"); | ||
|
||
if (code) { | ||
setUseSpinner(true); | ||
const { data, error } = await auth.client.POST("/users/github/code", { | ||
body: { code }, | ||
}); | ||
|
||
if (error) { | ||
addErrorAlert(error); | ||
setUseSpinner(false); | ||
} else { | ||
auth.login(data.api_key); | ||
setUseSpinner(false); | ||
} | ||
} | ||
})(); | ||
}, []); | ||
|
||
if (useSpinner) { | ||
return ( | ||
<CardContent className="flex justify-center"> | ||
<Spinner animation="border" /> | ||
</CardContent> | ||
); | ||
} | ||
|
||
return ( | ||
<> | ||
<CardContent>{isSignup ? <SignupForm /> : <LoginForm />}</CardContent> | ||
<CardFooter> | ||
<AuthProvider handleGithubSubmit={handleGithubSubmit} /> | ||
</CardFooter> | ||
<CardFooter> | ||
<BackButton | ||
onClick={() => setIsSignup((s) => !s)} | ||
label={ | ||
isSignup | ||
? "Already have an account? Login here." | ||
: "Don't have an account? Create a new account." | ||
} | ||
/> | ||
</CardFooter> | ||
</> | ||
); | ||
}; | ||
|
||
const AuthBlock = () => { | ||
return ( | ||
<Card className="w-[400px] shadow-md h-full mb-40"> | ||
<CardHeader> | ||
<Header /> | ||
</CardHeader> | ||
<AuthBlockInner /> | ||
</Card> | ||
); | ||
}; | ||
|
||
export default AuthBlock; |
2 changes: 1 addition & 1 deletion
2
frontend/src/components/ui/AuthProvider.tsx → ...tend/src/components/auth/AuthProvider.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { zodResolver } from "@hookform/resolvers/zod"; | ||
import { Button } from "components/ui/Button/Button"; | ||
import ErrorMessage from "components/ui/ErrorMessage"; | ||
import { Input } from "components/ui/Input/Input"; | ||
import { useState } from "react"; | ||
import { Eye } from "react-bootstrap-icons"; | ||
import { SubmitHandler, useForm } from "react-hook-form"; | ||
import { LoginSchema, LoginType } from "types"; | ||
|
||
const LoginForm = () => { | ||
const [showPassword, setShowPassword] = useState<boolean>(false); | ||
|
||
const { | ||
register, | ||
handleSubmit, | ||
formState: { errors }, | ||
} = useForm<LoginType>({ | ||
resolver: zodResolver(LoginSchema), | ||
}); | ||
|
||
const onSubmit: SubmitHandler<LoginType> = async (data: LoginType) => { | ||
// TODO: Add an api endpoint to send the credentials details to backend and email verification. | ||
console.log(data); | ||
}; | ||
|
||
return ( | ||
<form | ||
onSubmit={handleSubmit(onSubmit)} | ||
className="grid grid-cols-1 space-y-6" | ||
> | ||
{/* Email */} | ||
<div> | ||
<Input placeholder="Email" type="text" {...register("email")} /> | ||
{errors?.email && <ErrorMessage>{errors?.email?.message}</ErrorMessage>} | ||
</div> | ||
|
||
{/* Password */} | ||
<div className="relative"> | ||
<Input | ||
placeholder="Password" | ||
type={showPassword ? "text" : "password"} | ||
{...register("password")} | ||
/> | ||
{errors?.password && ( | ||
<ErrorMessage>{errors?.password?.message}</ErrorMessage> | ||
)} | ||
<div className="absolute inset-y-0 right-0 flex items-center pr-3"> | ||
<Eye | ||
onClick={() => setShowPassword((p) => !p)} | ||
className="cursor-pointer" | ||
/> | ||
</div> | ||
</div> | ||
|
||
<Button type="submit" className="w-full"> | ||
Login | ||
</Button> | ||
</form> | ||
); | ||
}; | ||
|
||
export default LoginForm; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { zodResolver } from "@hookform/resolvers/zod"; | ||
import { Button } from "components/ui/Button/Button"; | ||
import ErrorMessage from "components/ui/ErrorMessage"; | ||
import { Input } from "components/ui/Input/Input"; | ||
import { useState } from "react"; | ||
import { Eye } from "react-bootstrap-icons"; | ||
import { SubmitHandler, useForm } from "react-hook-form"; | ||
import { SignUpSchema, SignupType } from "types"; | ||
|
||
const SignupForm = () => { | ||
const [showPassword, setShowPassword] = useState<boolean>(false); | ||
const [showConfirmPassword, setShowConfirmPassword] = | ||
useState<boolean>(false); | ||
|
||
const { | ||
register, | ||
handleSubmit, | ||
formState: { errors }, | ||
} = useForm<SignupType>({ | ||
resolver: zodResolver(SignUpSchema), | ||
}); | ||
|
||
const onSubmit: SubmitHandler<SignupType> = async (data: SignupType) => { | ||
// TODO: Add an api endpoint to send the credentials details to backend and email verification. | ||
console.log(data); | ||
}; | ||
|
||
return ( | ||
<form | ||
onSubmit={handleSubmit(onSubmit)} | ||
className="grid grid-cols-1 space-y-6" | ||
> | ||
{/* Email */} | ||
<div> | ||
<Input placeholder="Email" type="text" {...register("email")} /> | ||
{errors?.email && <ErrorMessage>{errors?.email?.message}</ErrorMessage>} | ||
</div> | ||
|
||
{/* Password */} | ||
<div className="relative"> | ||
<Input | ||
placeholder="Password" | ||
type={showPassword ? "text" : "password"} | ||
{...register("password")} | ||
/> | ||
{errors?.password && ( | ||
<ErrorMessage>{errors?.password?.message}</ErrorMessage> | ||
)} | ||
<div className="absolute inset-y-0 right-0 flex items-center pr-3"> | ||
<Eye | ||
onClick={() => setShowPassword((p) => !p)} | ||
className="cursor-pointer" | ||
/> | ||
</div> | ||
</div> | ||
|
||
{/* Confirm Password */} | ||
<div className="relative"> | ||
<Input | ||
placeholder="Confirm Password" | ||
type={showConfirmPassword ? "text" : "password"} | ||
{...register("confirmPassword")} | ||
/> | ||
{errors?.confirmPassword && ( | ||
<ErrorMessage>{errors?.confirmPassword?.message}</ErrorMessage> | ||
)} | ||
<div className="absolute inset-y-0 right-0 flex items-center pr-3"> | ||
<Eye | ||
onClick={() => setShowConfirmPassword((p) => !p)} | ||
className="cursor-pointer" | ||
/> | ||
</div> | ||
</div> | ||
<Button type="submit" className="w-full"> | ||
Signup | ||
</Button> | ||
</form> | ||
); | ||
}; | ||
|
||
export default SignupForm; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { paths } from "gen/api"; | ||
import { useAlertQueue } from "hooks/alerts"; | ||
import { useAuthentication } from "hooks/auth"; | ||
import { useEffect, useState } from "react"; | ||
import { Col, Row, Spinner } from "react-bootstrap"; | ||
import ListingGridCard from "./ListingGridCard"; | ||
|
||
type ListingInfo = | ||
paths["/listings/batch"]["get"]["responses"][200]["content"]["application/json"]["listings"]; | ||
|
||
interface Props { | ||
listingIds: string[] | null; | ||
} | ||
|
||
const ListingGrid = (props: Props) => { | ||
const { listingIds } = props; | ||
const auth = useAuthentication(); | ||
const { addErrorAlert } = useAlertQueue(); | ||
|
||
const [listingInfo, setListingInfoResponse] = useState<ListingInfo | null>( | ||
null, | ||
); | ||
|
||
useEffect(() => { | ||
if (listingIds !== null && listingIds.length > 0) { | ||
(async () => { | ||
console.log("LISTING IDS:", listingIds); | ||
const { data, error } = await auth.client.GET("/listings/batch", { | ||
params: { | ||
query: { | ||
ids: listingIds, | ||
}, | ||
}, | ||
}); | ||
|
||
if (error) { | ||
addErrorAlert(error); | ||
return; | ||
} | ||
|
||
setListingInfoResponse(data.listings); | ||
})(); | ||
} | ||
}, [listingIds]); | ||
|
||
return ( | ||
<Row className="mt-5"> | ||
{listingIds === null ? ( | ||
<Col className="text-center"> | ||
<Spinner animation="border" /> | ||
</Col> | ||
) : ( | ||
listingIds.map((listingId) => ( | ||
<Col key={listingId} lg={2} md={3} sm={6} xs={12}> | ||
<ListingGridCard listingId={listingId} listingInfo={listingInfo} /> | ||
</Col> | ||
)) | ||
)} | ||
</Row> | ||
); | ||
}; | ||
|
||
export default ListingGrid; |
Oops, something went wrong.