Skip to content

Commit

Permalink
add login
Browse files Browse the repository at this point in the history
  • Loading branch information
danieleguido committed Mar 15, 2024
1 parent 2dec133 commit 487c69b
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 24 deletions.
2 changes: 1 addition & 1 deletion src/components/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const Header = () => {
get your API token
</Link>
</Nav>
<Nav className="ms-auto">
<Nav className="ms-auto align-items-center">
<Form inline="true">
<InputGroup>
<Form.Control
Expand Down
9 changes: 8 additions & 1 deletion src/components/ModalLogin.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import React, { useRef } from "react"
import ModalView from "./ModalView"
import { ModalLoginView } from "../store"
import { ModalLoginView, useBrowserStore, usePersistentStore } from "../store"
import { Button, Form, Modal } from "react-bootstrap"
import { useMutation } from "@tanstack/react-query"
import axios from "axios"

const ModalLogin = ({ onClose, ...props }) => {
const setAuthenticatedUser = usePersistentStore(
(store) => store.setAuthenticatedUser
)
const setView = useBrowserStore((store) => store.setView)
const formPayload = useRef({
email: "",
password: "",
Expand All @@ -24,6 +28,9 @@ const ModalLogin = ({ onClose, ...props }) => {
password: "",
strategy: "local",
}
setAuthenticatedUser(res.data.user, res.data.accessToken)
// setView null is going to close ModalView, see component useEffect behaviour.
setView(null)
return res.data
})
.catch((err) => {
Expand Down
Empty file added src/components/ModalSignup.js
Empty file.
63 changes: 47 additions & 16 deletions src/components/UserArea.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,62 @@ import { useQuery } from "@tanstack/react-query"
import axios from "axios"
import React from "react"
import { Button } from "react-bootstrap"
import { ModalLoginView, useBrowserStore } from "../store"
import { ModalLoginView, useBrowserStore, usePersistentStore } from "../store"
import UserCard from "./UserCard"

const UserArea = () => {
const setView = useBrowserStore((state) => state.setView)
const [view, setView] = useBrowserStore((state) => [
state.view,
state.setView,
])
const [user, token, resetUser, patchUser] = usePersistentStore((state) => [
state.user,
state.token,
state.resetUser,
])
const { status, data, error } = useQuery({
queryKey: ["me"],
queryFn: () => axios.get(`/api/me`),
queryFn: () =>
axios
.get("/api/me", {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((res) => res.data),
retry: false,
refetchOnMount: false,
refetchOnReconnect: false,
enabled: user === null && token !== null,
})

console.log("[UserArea]", status, data, error)
if (status === "error" && error.response?.status === 401) {
console.warn("[UserArea] token is incorrect. ", error.response.data)
// clean up the token(s) and user(s) from the store
resetUser()
} else if (status === "success") {
patchUser(data)
}
console.info("[UserArea] user", user, "status", status)
return (
<div className="UserArea">
<Button
size="sm"
variant="transparent"
onClick={() => setView(ModalLoginView)}
>
Log in
</Button>
<Button size="sm" variant="transparent">
Sign up {process.env.GATSBY_IMPRESSO_API_URL}
</Button>
<div className="UserArea me-3 d-flex">
{user !== null ? (
<>
<UserCard user={user} />
</>
) : (
<>
<Button
size="sm"
variant="transparent"
onClick={() => setView(ModalLoginView)}
>
Log in
</Button>
<Button size="sm" variant="transparent">
Sign up {view}
</Button>
</>
)}
</div>
)
}
Expand Down
4 changes: 4 additions & 0 deletions src/components/UserCard.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.UserCard h3 {
font-size: inherit;
font-variation-settings: "wght" 550;
}
24 changes: 24 additions & 0 deletions src/components/UserCard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from "react"
import "./UserCard.css"
import Avatar from "boring-avatars"

const UserCard = ({ user }) => {
return (
<div className="UserCard d-flex align-items-center">
<div className="me-2">
<Avatar
size={40}
name={user.username}
variant="pixel"
colors={user.profile?.pattern}
/>
</div>
<div>
<h3 className="m-0">{user.username}</h3>
<p className="m-0">{user.isStaff ? "staff" : "researcher"} </p>
</div>
</div>
)
}

export default UserCard
17 changes: 11 additions & 6 deletions src/components/Wall.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import { nord } from "@uiw/codemirror-theme-nord"
import { python } from "@codemirror/lang-python"

const CodeSample = `
from impresso-py import impresso
from impresso import api
print(impresso.version())
print(api.version())
results = impresso.search("moon landing")
results = api.search("moon landing")
`

const Wall = () => {
Expand Down Expand Up @@ -88,7 +88,6 @@ const Wall = () => {
) : (
<p>No highlighted collections found.</p>
)}
<CollectionCard name="notebooks-we-are-testing-right-now"></CollectionCard>
</Col>
<Col>
<h1 className="display-3 ">Give your media monitoring a boost.</h1>
Expand Down Expand Up @@ -121,7 +120,11 @@ const Wall = () => {
<Col className=" d-flex justify-content-center align-items-end ">
<h2 className="border-bottom border-dark w-100">Tutorials</h2>
</Col>
<Col></Col>
<Col className=" d-flex justify-content-center align-items-end ">
<h2 className="border-bottom border-dark w-100">
From the community
</h2>
</Col>
</Row>
<Row>
<Col></Col>
Expand All @@ -130,7 +133,9 @@ const Wall = () => {
<TutorialCard name={node.name} key={node.name} />
))}
</Col>
<Col></Col>
<Col>
<CollectionCard name="notebooks-we-are-testing-right-now"></CollectionCard>
</Col>
</Row>
</Container>
)
Expand Down
43 changes: 43 additions & 0 deletions src/store.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { use } from "marked"
import { create } from "zustand"
import { createJSONStorage, persist } from "zustand/middleware"

export const ModalDraftView = "draft"
export const ModalForkNotebookView = "fork-notebook"
Expand Down Expand Up @@ -50,3 +52,44 @@ export const useDataStore = create((set, get) => ({
},
isReady: false,
}))

export const usePersistentStore = create(
persist(
(set, get) => ({
user: null,
token: null,
rememberCredentials: false,
setAuthenticatedUser(user, token) {
set({ user, token })
},
reset() {
localStorage.removeItem("feathers-jwt")
set({ user: null, token: null })
},
patchUser(user) {
// get the current user and patch it with the new user
const currentUser = get().user
set({
user: {
...currentUser,
...user,
},
})
},
}),
{
name: "impresso-datalab",
storage: createJSONStorage(() => localStorage), // (optional) by default, 'localStorage' is used
}
)
)

// get fresh data from the localstorage
const existingToken = localStorage.getItem("feathers-jwt")

if (existingToken && usePersistentStore.getState().token === null) {
console.info("[usePersistentStore] use existing token from feathers-jwt")
usePersistentStore.setState({ token: existingToken })
} else {
console.info("[usePersistentStore] use fresh token")
}

0 comments on commit 487c69b

Please sign in to comment.