From 45039d356f749266fec30da55ea6d272b48c721d Mon Sep 17 00:00:00 2001 From: Pijus Kamandulis Date: Sun, 6 Oct 2024 15:15:36 +0300 Subject: [PATCH] Write a POC of estimation session --- .prettierrc | 7 + bun.lockb | Bin 73385 -> 133154 bytes eslint.config.js | 23 ++- package.json | 4 + src/App.tsx | 35 ---- src/constants.ts | 5 + src/lib/appwrite.ts | 11 ++ src/lib/context/estimationSession.tsx | 257 ++++++++++++++++++++++++++ src/lib/context/user.tsx | 76 ++++++++ src/main.tsx | 69 ++++++- src/pages/CreateEstimationSession.tsx | 48 +++++ src/pages/EstimationSession.tsx | 110 +++++++++++ src/{App.css => pages/Home.css} | 8 - src/pages/Home.tsx | 46 +++++ src/pages/Login.tsx | 72 ++++++++ 15 files changed, 714 insertions(+), 57 deletions(-) create mode 100644 .prettierrc delete mode 100644 src/App.tsx create mode 100644 src/constants.ts create mode 100644 src/lib/appwrite.ts create mode 100644 src/lib/context/estimationSession.tsx create mode 100644 src/lib/context/user.tsx create mode 100644 src/pages/CreateEstimationSession.tsx create mode 100644 src/pages/EstimationSession.tsx rename src/{App.css => pages/Home.css} (89%) create mode 100644 src/pages/Home.tsx create mode 100644 src/pages/Login.tsx diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..4a95970 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "trailingComma": "all", + "singleQuote": true, + "endOfLine": "lf", + "tabWidth": 2, + "semi": true +} diff --git a/bun.lockb b/bun.lockb index f728b305a4371f1928445c258250b7debf22e4cd..82a62a3e015a9c744b1882199f4103e90667f5ee 100755 GIT binary patch literal 133154 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 G-2WT+dM - -

Vite + React

-
- -

- Edit src/App.tsx and save to test HMR -

-
-

- Click on the Vite and React logos to learn more -

- - ) -} - -export default App diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 0000000..0f1a84b --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,5 @@ +// TODO: Think about moving to .env +export const APPWRITE_ENDPOINT = 'https://cloud.appwrite.io/v1'; +export const APPWRITE_PROJECT_ID = 'scrummie-poker'; +export const APPWRITE_DATABASE_ID = 'scrummie-poker-db'; +export const APPWRITE_ESTIMATION_SESSION_COLLECTION_ID = 'estimation-session'; diff --git a/src/lib/appwrite.ts b/src/lib/appwrite.ts new file mode 100644 index 0000000..fa5b8d3 --- /dev/null +++ b/src/lib/appwrite.ts @@ -0,0 +1,11 @@ +import { Client, Account, Databases } from 'appwrite'; +import { APPWRITE_ENDPOINT, APPWRITE_PROJECT_ID } from '../constants'; + +export const client = new Client(); + +client.setEndpoint(APPWRITE_ENDPOINT).setProject(APPWRITE_PROJECT_ID); + +export { ID } from 'appwrite'; + +export const account = new Account(client); +export const databases = new Databases(client); diff --git a/src/lib/context/estimationSession.tsx b/src/lib/context/estimationSession.tsx new file mode 100644 index 0000000..99f57f1 --- /dev/null +++ b/src/lib/context/estimationSession.tsx @@ -0,0 +1,257 @@ +import { + createContext, + PropsWithChildren, + useContext, + useEffect, + useState, +} from 'react'; +import { client, databases } from '../appwrite'; +import { ID, Models, Query } from 'appwrite'; +import { + APPWRITE_DATABASE_ID, + APPWRITE_ESTIMATION_SESSION_COLLECTION_ID, +} from '../../constants'; + +interface EstimationSessionType extends Models.Document { + UserId: string; + Name: string; + Tickets: string[]; + SessionState: string; +} + +interface EstimationSessionTicket { + Id: string; + Name: string; +} + +interface SessionStateType { + CurrentTicketId: string; + VotesRevealed: boolean; + Votes: { + UserId: string; + Estimate: number; + }[]; +} + +interface EstimationSessionsContextType { + current: EstimationSessionType[]; + add: ( + estimationSession: Omit, + ) => Promise; + remove: (id: string) => Promise; + addTicket: ( + sessionId: string, + ticket: Omit, + ) => Promise; + getTickets: (sessionId: string) => EstimationSessionTicket[]; + selectTicket: (sessionId: string, ticketId: string) => Promise; + getState: (sessionId: string) => SessionStateType; + voteEstimate: ( + sessionId: string, + ticketId: string, + estimate: number, + userId: string, + ) => Promise; + revealVotes: (sessionId: string) => Promise; +} + +const EstimationSessionsContext = createContext< + EstimationSessionsContextType | undefined +>(undefined); + +export function useEstimationSessions() { + return useContext(EstimationSessionsContext); +} + +export function EstimationSessionProvider(props: PropsWithChildren) { + const [estimationSessions, setEstimationSessions] = useState< + EstimationSessionType[] + >([]); + + const add = async ( + estimationSession: Omit, + ) => { + const response = await databases.createDocument( + APPWRITE_DATABASE_ID, + APPWRITE_ESTIMATION_SESSION_COLLECTION_ID, + ID.unique(), + estimationSession, + ); + setEstimationSessions((estimationSessions) => + [response, ...estimationSessions].slice(0, 10), + ); + }; + + const remove = async (id: string) => { + await databases.deleteDocument( + APPWRITE_DATABASE_ID, + APPWRITE_ESTIMATION_SESSION_COLLECTION_ID, + id, + ); + setEstimationSessions((estimationSessions) => + estimationSessions.filter( + (estimationSession) => estimationSession.$id !== id, + ), + ); + await init(); + }; + + const addTicket = async ( + sessionId: string, + ticket: Omit, + ) => { + const currentSession = estimationSessions.find((x) => x.$id === sessionId); + const response = await databases.updateDocument( + APPWRITE_DATABASE_ID, + APPWRITE_ESTIMATION_SESSION_COLLECTION_ID, + sessionId, + { + Tickets: currentSession?.Tickets.concat([ + JSON.stringify({ + ...ticket, + Id: crypto.randomUUID(), + }), + ]), + }, + ); + setEstimationSessions((estimationSessions) => + estimationSessions + .filter((x) => x.$id != sessionId) + .concat([response]) + .slice(0, 10), + ); + }; + + const getTickets = (sessionId: string) => { + return ( + estimationSessions + .find((x) => x.$id === sessionId) + ?.Tickets.map((x) => JSON.parse(x)) ?? [] + ); + }; + + const selectTicket = async (sessionId: string, ticketId: string) => { + const response = await databases.updateDocument( + APPWRITE_DATABASE_ID, + APPWRITE_ESTIMATION_SESSION_COLLECTION_ID, + sessionId, + { + SessionState: JSON.stringify({ + CurrentTicketId: ticketId, + }), + }, + ); + setEstimationSessions((estimationSessions) => + estimationSessions + .filter((x) => x.$id != sessionId) + .concat([response]) + .slice(0, 10), + ); + }; + + const getState = (sessionId: string): SessionStateType => { + return JSON.parse( + estimationSessions.find((x) => x.$id === sessionId)?.SessionState ?? '{}', + ); + }; + + const voteEstimate = async ( + sessionId: string, + ticketId: string, + estimate: number, + userId: string, + ) => { + const currentState = getState(sessionId); + const newVotes = (currentState.Votes ?? []) + .filter((x) => x.UserId !== userId) + .concat([ + { + Estimate: estimate, + UserId: userId, + }, + ]); + const response = await databases.updateDocument( + APPWRITE_DATABASE_ID, + APPWRITE_ESTIMATION_SESSION_COLLECTION_ID, + sessionId, + { + SessionState: JSON.stringify({ + CurrentTicketId: ticketId, + Votes: newVotes, + }), + }, + ); + setEstimationSessions((estimationSessions) => + estimationSessions + .filter((x) => x.$id != sessionId) + .concat([response]) + .slice(0, 10), + ); + }; + + const revealVotes = async (sessionId: string) => { + const currentState = getState(sessionId); + const response = await databases.updateDocument( + APPWRITE_DATABASE_ID, + APPWRITE_ESTIMATION_SESSION_COLLECTION_ID, + sessionId, + { + SessionState: JSON.stringify({ + ...currentState, + VotesRevealed: true, + }), + }, + ); + setEstimationSessions((estimationSessions) => + estimationSessions + .filter((x) => x.$id != sessionId) + .concat([response]) + .slice(0, 10), + ); + }; + + const init = async () => { + const response = await databases.listDocuments( + APPWRITE_DATABASE_ID, + APPWRITE_ESTIMATION_SESSION_COLLECTION_ID, + [Query.orderDesc('$createdAt'), Query.limit(10)], + ); + setEstimationSessions(response.documents); + + client.subscribe( + [ + `databases.${APPWRITE_DATABASE_ID}.collections.${APPWRITE_ESTIMATION_SESSION_COLLECTION_ID}.documents`, + ], + (payload) => { + setEstimationSessions((estimationSessions) => + estimationSessions + .filter((x) => x.$id != payload.payload.$id) + .concat([payload.payload]) + .slice(0, 10), + ); + }, + ); + }; + + useEffect(() => { + init(); + }, []); + + return ( + + {props.children} + + ); +} diff --git a/src/lib/context/user.tsx b/src/lib/context/user.tsx new file mode 100644 index 0000000..c30f958 --- /dev/null +++ b/src/lib/context/user.tsx @@ -0,0 +1,76 @@ +import { ID, Models } from 'appwrite'; +import { + createContext, + PropsWithChildren, + useContext, + useEffect, + useState, +} from 'react'; +import { account } from '../appwrite'; + +interface UserContextType { + current: Models.Session | Models.User | null; + login: (email: string, password: string) => Promise; + logout: () => Promise; + register: (email: string, password: string) => Promise; + loginAsGuest: () => Promise; +} + +const UserContext = createContext(undefined); + +export const useUser = () => { + const context = useContext(UserContext); + if (!context) { + throw new Error('useUser must be used within a UserProvider'); + } + return context; +}; + +export const UserProvider = (props: PropsWithChildren) => { + const [user, setUser] = useState< + Models.Session | Models.User | null + >(null); + + const login = async (email: string, password: string) => { + const loggedIn = await account.createEmailPasswordSession(email, password); + setUser(loggedIn); + window.location.replace('/'); // you can use different redirect method for your application + }; + + const logout = async () => { + await account.deleteSession('current'); + setUser(null); + }; + + const register = async (email: string, password: string) => { + await account.create(ID.unique(), email, password); + await login(email, password); + }; + + const loginAsGuest = async () => { + const session = await account.createAnonymousSession(); + setUser(session); + window.location.replace('/'); // you can use different redirect method for your application + }; + + const init = async () => { + try { + const loggedIn = await account.get(); + setUser(loggedIn); + } catch (err) { + setUser(null); + } + }; + + useEffect(() => { + init(); + }, []); + + return ( + + {props.children} + + ); +}; diff --git a/src/main.tsx b/src/main.tsx index 6f4ac9b..aa72c55 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,10 +1,67 @@ -import { StrictMode } from 'react' -import { createRoot } from 'react-dom/client' -import App from './App.tsx' -import './index.css' +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; +import './index.css'; +import { + createRootRoute, + createRoute, + createRouter, + RouterProvider, +} from '@tanstack/react-router'; +import Home from './pages/Home'; +import { UserProvider } from './lib/context/user'; +import Login from './pages/Login'; +import EstimationSession from './pages/EstimationSession'; +import CreateEstimationSession from './pages/CreateEstimationSession'; +import { EstimationSessionProvider } from './lib/context/estimationSession'; + +const rootRoute = createRootRoute(); + +const indexRoute = createRoute({ + path: '/', + component: Home, + getParentRoute: () => rootRoute, +}); + +const loginRoute = createRoute({ + path: 'login', + component: Login, + getParentRoute: () => rootRoute, +}); + +const createEstimationSessionRoute = createRoute({ + path: 'estimate/new', + component: CreateEstimationSession, + getParentRoute: () => rootRoute, +}); + +const estimationSessionRoute = createRoute({ + path: 'estimate/session/$sessionId', + component: EstimationSession, + getParentRoute: () => rootRoute, +}); + +const router = createRouter({ + routeTree: rootRoute.addChildren([ + indexRoute, + loginRoute, + createEstimationSessionRoute, + estimationSessionRoute, + ]), +}); + +declare module '@tanstack/react-router' { + interface Register { + router: typeof router; + } +} createRoot(document.getElementById('root')!).render( - + + {/* TODO: Move ctx providers to layout */} + + + + , -) +); diff --git a/src/pages/CreateEstimationSession.tsx b/src/pages/CreateEstimationSession.tsx new file mode 100644 index 0000000..e19866b --- /dev/null +++ b/src/pages/CreateEstimationSession.tsx @@ -0,0 +1,48 @@ +import { useForm } from '@tanstack/react-form'; +import { useEstimationSessions } from '../lib/context/estimationSession'; +import { useUser } from '../lib/context/user'; + +const CreateEstimationSession = () => { + const user = useUser(); + const estimationSessions = useEstimationSessions(); + const form = useForm({ + defaultValues: { + name: '', + }, + onSubmit: async ({ value }) => { + await estimationSessions?.add({ + Name: value.name, + UserId: user.current?.$id, + }); + }, + }); + + return ( + <> +

Create Estimation Session

+
{ + e.preventDefault(); + e.stopPropagation(); + form.handleSubmit(); + }} + > + ( + field.handleChange(e.target.value)} + /> + )} + /> + + + + ); +}; + +export default CreateEstimationSession; diff --git a/src/pages/EstimationSession.tsx b/src/pages/EstimationSession.tsx new file mode 100644 index 0000000..6282520 --- /dev/null +++ b/src/pages/EstimationSession.tsx @@ -0,0 +1,110 @@ +import { getRouteApi } from '@tanstack/react-router'; +import { useEstimationSessions } from '../lib/context/estimationSession'; +import { useForm } from '@tanstack/react-form'; +import { useUser } from '../lib/context/user'; + +const route = getRouteApi('/estimate/session/$sessionId'); + +const EstimationSession = () => { + const { sessionId } = route.useParams(); + const user = useUser(); + const estimationSessions = useEstimationSessions(); + const estimationSession = estimationSessions?.current.find( + (x) => x.$id == sessionId, + ); + const tickets = estimationSessions?.getTickets(sessionId); + const currentState = estimationSessions?.getState(sessionId); + + const createTicketForm = useForm({ + defaultValues: { + name: '', + }, + onSubmit: async ({ value }) => { + await estimationSessions?.addTicket(sessionId, { + Name: value.name, + }); + }, + }); + + return ( + <> +

Estimation Session - {estimationSession?.Name}

+
+

Tasks

+ {tickets?.map((x) => ( +
+ {x.Id} - {x.Name} + +
+ ))} +
{ + e.preventDefault(); + e.stopPropagation(); + createTicketForm.handleSubmit(); + }} + > + ( + field.handleChange(e.target.value)} + /> + )} + /> + + +
+ {currentState?.CurrentTicketId && ( +
+

+ {currentState.CurrentTicketId} -{' '} + {tickets?.find((x) => x.Id === currentState.CurrentTicketId)?.Name} +

+ {[0.5, 1, 2, 3, 5, 8, 13, 21].map((estimate) => ( + + ))} + {currentState.VotesRevealed ? ( + <> +

Votes

+
    + {currentState.Votes.map((vote) => ( +
  • + {vote.UserId} - {vote.Estimate} +
  • + ))} +
+ + ) : ( + + )} +
+ )} +
Session Id: {sessionId}
+ + ); +}; + +export default EstimationSession; diff --git a/src/App.css b/src/pages/Home.css similarity index 89% rename from src/App.css rename to src/pages/Home.css index b9d355d..cf763fc 100644 --- a/src/App.css +++ b/src/pages/Home.css @@ -32,11 +32,3 @@ animation: logo-spin infinite 20s linear; } } - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx new file mode 100644 index 0000000..38bf87b --- /dev/null +++ b/src/pages/Home.tsx @@ -0,0 +1,46 @@ +import reactLogo from '../assets/react.svg'; +import viteLogo from '/vite.svg'; +import './Home.css'; +import { Link } from '@tanstack/react-router'; +import { useUser } from '../lib/context/user'; +import { useEstimationSessions } from '../lib/context/estimationSession'; + +function Home() { + const user = useUser(); + const estimationSessions = useEstimationSessions(); + + return ( + <> + +

Scrummie-Poker

+ +
    +
  • + Login +
  • +
  • + Create Estimation Session +
  • +
+
User Id: {user.current?.$id}
+ +
+

Estimation sessions

+ {estimationSessions?.current.map((session) => ( + + {session.Name} + + ))} +
+ + ); +} + +export default Home; diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx new file mode 100644 index 0000000..2ca76c5 --- /dev/null +++ b/src/pages/Login.tsx @@ -0,0 +1,72 @@ +import { useForm } from '@tanstack/react-form'; +import { useUser } from '../lib/context/user'; + +const Login = () => { + const user = useUser(); + const form = useForm({ + defaultValues: { + email: '', + password: '', + }, + onSubmit: async ({ value }) => { + console.log({ value }); + }, + }); + + return ( + <> +

Login or register

+
+ ( + field.handleChange(e.target.value)} + /> + )} + /> + ( + field.handleChange(e.target.value)} + /> + )} + /> +
+ + +
+ + + + ); +}; + +export default Login;