Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion static/client/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { QueryClient, QueryClientProvider } from "react-query";

import "./App.scss";
import config from "./config";
import Main from "./pages/Main";

const queryClient = new QueryClient();
const queryClient = new QueryClient({
defaultOptions: {
queries: config.api.FETCH_OPTIONS,
},
});

const App: React.FC = () => {
return (
Expand Down
12 changes: 11 additions & 1 deletion static/client/components/Navigation/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ import NavigationItems from "./NavigationItems";

import NavigationCollapseToggle from "@/components/Navigation/NavigationCollapseToggle";
import SiteSelector from "@/components/SiteSelector";
import { useStore } from "@/store";

const Navigation = (): JSX.Element => {
const navigate = useNavigate();
const [isCollapsed, setIsCollapsed] = useState(true);
const [user, setUser] = useStore((state) => [state.user, state.setUser]);

const logout = useCallback(() => {
setUser(null);
window.open("/logout", "_self");
}, []);
}, [setUser]);

const handleNewPageClick = useCallback(() => {
navigate("/app/new-webpage");
Expand Down Expand Up @@ -55,6 +58,13 @@ const Navigation = (): JSX.Element => {
<NavigationItems />
</div>
<div className="p-panel__footer p-side-navigation--icons">
<div className="u-no-margin u-truncate p-side-navigation__label">
<span>{user?.name}</span>
</div>
<div className="p-text--small u-text--muted u-truncate p-side-navigation__label">
<span>{user?.email}</span>
</div>
<hr className="p-rule" />
<Button appearance="base" className="p-side-navigation__link" onClick={logout}>
<i className="p-icon--logout is-light p-side-navigation__icon" />
<span className="p-side-navigation__label">Log out</span>
Expand Down
2 changes: 1 addition & 1 deletion static/client/components/Navigation/_Navigation.scss
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
}

.p-panel__content {
height: calc(100vh - 340px);
height: calc(100vh - 440px);
overflow: auto;

@media (min-width: $breakpoint-small) and (max-width: $breakpoint-large) {
Expand Down
2 changes: 2 additions & 0 deletions static/client/pages/Main/Main.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";

import MainLayout from "@/components/MainLayout";
import { useAuth } from "@/services/api/hooks/auth";
import { usePages } from "@/services/api/hooks/pages";
import { RoutesServices } from "@/services/routes";

const Main = (): React.ReactNode => {
useAuth();
const { data } = usePages();

return (
Expand Down
1 change: 1 addition & 0 deletions static/client/services/api/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const ENDPOINTS = {
createNewPage: "/api/create-page",
requestChanges: "/api/request-changes",
requestRemoval: "/api/remove-webpage",
currentUser: "/api/current-user",
};

export const REST_TYPES = {
Expand Down
26 changes: 26 additions & 0 deletions static/client/services/api/hooks/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useQuery } from "react-query";

import { getCurrentUser } from "@/services/api/services/users";
import type { IApiBasicError, IUseQueryHookRest } from "@/services/api/types/query";
import type { IUser } from "@/services/api/types/users";
import { useStore } from "@/store";

export function useAuth(): IUseQueryHookRest<IUser> {
const [user, setUser] = useStore((state) => [state.user ?? undefined, state.setUser]);

const result = useQuery<IUser, IApiBasicError>("loggedInUser", async () => {
try {
const res = await getCurrentUser();
setUser(res);
return res;
} catch (error) {
throw new Error("Failed to fetch current user");
}
});

const isLoading = result.isLoading;
const isFetching = result.isFetching;
const error = result.error;

return { isLoading, data: user, error, isFetching };
}
6 changes: 5 additions & 1 deletion static/client/services/api/partials/UsersApiClass.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { BasicApiClass } from "./BasicApiClass";

import { ENDPOINTS, REST_TYPES } from "@/services/api/constants";
import { type IUsersResponse } from "@/services/api/types/users";
import type { IUser, IUsersResponse } from "@/services/api/types/users";

export class UsersApiClass extends BasicApiClass {
public getUsers(username: string): Promise<IUsersResponse> {
return this.callApi<IUsersResponse>(ENDPOINTS.getUsers(username), REST_TYPES.GET);
}

public getCurrentUser(): Promise<IUser> {
return this.callApi<{ data: IUser }>(ENDPOINTS.currentUser, REST_TYPES.GET).then((res) => res.data);
}
}
6 changes: 5 additions & 1 deletion static/client/services/api/services/users.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { api } from "@/services/api";
import type { IUsersResponse } from "@/services/api/types/users";
import type { IUser, IUsersResponse } from "@/services/api/types/users";

export const getUsers = async (username: string): Promise<IUsersResponse> => {
return api.users.getUsers(username);
};

export const getCurrentUser = async (): Promise<IUser> => {
return api.users.getCurrentUser();
};

export * as UsersServices from "./users";
5 changes: 3 additions & 2 deletions static/client/store/types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { type IPagesResponse } from "@/services/api/types/pages";
import { type IUser } from "@/services/api/types/users";

export interface IStore {
selectedProject: IPagesResponse["data"] | null;
user: string | null;
user: IUser | null;
setSelectedProject: (s: IPagesResponse["data"]) => void;
setUser: (u: string) => void;
setUser: (u: IUser | null) => void;
}
Loading