-
Notifications
You must be signed in to change notification settings - Fork 3
Frontend
The frontend is written entirely in typescript.
Before you begin, you might want to familiarize yourself with the following:
- https://react.dev/
- https://reactrouter.com/en/main
- https://supabase.com/docs/reference/javascript/initializing
- https://www.typescriptlang.org/docs/
This wiki assumes that you are familiar with using these technologies.
There are also some constants you should be aware of in src/constants.ts
PUBLIC_URL = the "domain" of the website
SUPABASE_URL = the url where supabase is hosted. it is usually on port 8000.
SUPABASE_ANON_KEY = the api key that "anonymous users" use. this key is safe to give out as it is how anonymous users (those who are not signed in)
access parts of the website.
These are set to work with your local supabase (except for the ANON_KEY), but if you want to develop with the production database, you should replace these with the values for the production database/
Here's a list of some stuff you should be aware of. This is not an extensive list. You should look through the files yourself, this is just to get you started.
- package.json
- where all the dependencies are stored (libraries that the frontend uses)
-
src/
- the folder with all the code of the website, short for "source".-
index.tsx
- The entire website is contained within this one file. It importsApp.tsx
which contains all our pages and routes. -
App.tsx
- Our entire "App". Basically,<Pages />
contains all the pages of our website. Assuming you have react knowledge, the stuff around it are "Providers". These Providers pass down "Contexts", which are just Javascript objects that are accessible to the entire website. For example, we have a ThemeProvider that passes an Object that stores all the color codes of our website (and is used by React MUI to automatically color components). There is also a UserProvider which passes down an Object that stores the session information of the current user that is accessible throughout the site. You can examine the files that use these contexts to learn how they are used, and you should look at the React docs. -
supabaseClient.ts
- Our frontend supabase client. We import this in MANY, many files because it is how we interact with our database. -
utils/
- useful functions used repeatedly in the site. -
comps/
- react "components" that are used repeatedly in the site.-
ui/
- random ui components -
admin/
- components for the admin page -
pages/
- components for each page. Each page has its own components folder atcomps/<page_name>/
. -
context/
- React contexts.
-
-
@types/
- our typescript types. there is a .d. that allows us to use these types in every file. -
pages/
- where all the pages for the site are stored.-
index.ts
- The React Router for all the pages in our site. -
orgs/
,admin/
,modules/
also have their own react routers. Here's a fun trick: you can use a React Router inside of a React Router. While we have one main one that manages all the pages, at the time of this writing, these 3 routes have their own react routers that manage subpages. This lets us do things such as restrict urls with admin/ in them to only admins, or allow us to pass OrgContexts when viewing specific organizations at orgs/url.modules/
includes additional features such as attendance, and we have other modules planned such as opportunities, votes, etc.
-
-
Contexts are such an important aspect of this project, it would be good if you knew how to use them. Here's two examples, one where we use contexts for User data and one where we use Contexts to hold Org information.
In src/comps/context/UserProvider
, we return a UserContext.
/* this is the value that is passed into the context */
const value = {
signed_in: true,
admin: isAdmin,
id: user.id,
first_name: user.first_name,
last_name: user.last_name,
email: user.email,
picture: user.picture,
grade: user.grade,
memberships: user.memberships,
is_faculty: user.is_faculty,
active: user.active,
}
return (
<UserContext.Provider value={value}>{children}</UserContext.Provider>
);
UserContext.tsx
import React from "react";
const UserContext = React.createContext<UserContextType>({
signed_in: false,
admin: false,
id: -1,
first_name: "",
last_name: "",
email: "",
picture: "",
grade: -1,
memberships: [],
is_faculty: false,
active: false,
});
export default UserContext;
{children}
is just everything wrapped within a React Component, so if we look at the main React Router for the site src/App.tsx
<UserProvider>
<Pages />
</UserProvider>
as you can see, we wrap all of our pages with the UserProvider. Now, when we want to access the user information, we can just do this in ANY file within the pages. INCLUDING components
const randomComponent = () => {
const user = useContext(UserContext);
return (
<p>Hi ${user.first_name}</p>
)
}
Org works the same way, except the values are passed in pages/orgs/index.tsx
, which is the OrgRouter.
Therefore, any page with /orgs/ in the url is able to access the context that contains the information of the current Org it is in.
If you look at comps/pages/orgs
, you will notice that some components use the OrgContext to get org data. Be careful, these components
assume that they are going to be used in a page with /org/
in the url, but if they were used out of that situation, they wouldn't be able
to fetch the context.
We use React MUI and a theme provider. If you aren't doing massive theme changes, you probably don't need to worry about this. You can use React MUI components and they will color automatically. It would be good to learn about React MUI though. It basically comes with a bunch of prebuilt components that we use. For CSS, we use inline CSS styles. We sacrifice a bit of performance for a developer experience that is more modular and independent of other people.
Starting with our UI Revamp, we will be using Radix UI for which docs can be found here: https://www.radix-ui.com/themes/docs/overview/getting-started
For imported image textures <30KB, they are to be placed in the textures folder; for images >30KB or icons, they are to be placed in the public folder. We are rolling out changes incrementally, based on pages.
To interact with the database, import supabase from src/supabaseClient.ts
.
Just observe the other files to see how we fetch data, and look at the supabase docs.
You have 4 operations, inserting (creating row), updating, selecting, and deleting.
You do NOT need to worry about permissions. Row level security on our database handles everything. This is because when making a request with the supabase client, it sends the token of the signed in user and automatically validates everything. Thus, you just need to call the request and if it was something you weren't supposed to do, it won't let you do it.
We also have database functions, which are functions in our postgres database that replace difficult queries with a function, and we also have edge functions which are similar to routes in a backend such as Express.js, giving us a REST api as well.
Interacting with the database is truly self explanatory! Just observe how we do it before! It is almost as if you are interacting with local files on your computer. If you only end up using the 4 operations listed above, you don't even need to touch the backend at all while being able to make complicated features.
If you do have to edit the backend, make sure to set the REACT_APP_SUPABASE_URL
and the REACT_APP_SUPABASE_ANON_KEY
environment variables in your IDE to point towards the development Supabase instance. Never commit these changes, you may only edit constants.ts
as a last resort.
If you don't want to run your own backend, and you want to run a localhost:3000 react server that uses the production database, you need to sign in via the console. If you try to sign in using the sign in with google button, the production database will just send you back to the production frontend instead of your development frontend.
Steps
- Step 1: Go to the production website https://epsilon.stuysu.org/ and sign in with the account you want to log in with.
- Step 2: Open the developer console on the production site. Enter the command
window.localStorage.getItem("sb-base-auth-token")
to grab your user authentication token (WITH the quotes on the outside). - Step 3: Switch back to your development site. Enter the command
window.localStorage.setItem("sb-base-auth-token", <TOKEN>)
, with<TOKEN>
being replaced by the text. (You may have to paste with Ctrl-SHIFT-V in order to prevent the console from automatically escaping any quotes). - Step 4: Refresh the page, you should be signed in!