diff --git a/src/api_client/api.ts b/src/api_client/api.ts index bcc9cc62..9af5f96f 100644 --- a/src/api_client/api.ts +++ b/src/api_client/api.ts @@ -57,6 +57,7 @@ export enum Endpoints { fetchStorageStats = "fetchStorageStats", fetchImageTag = "fetchImageTag", generateAutoAlbumTitle = "generateAutoAlbumTitle", + logout = "logout", } const baseQuery = fetchBaseQuery({ @@ -144,6 +145,13 @@ export const api = createApi({ return data; }, }), + [Endpoints.logout]: builder.mutation({ + query: () => ({ + url: "/auth/token/blacklist/", + method: "POST", + body: { refresh: new Cookies().get("refresh") }, + }), + }), [Endpoints.isFirstTimeSetup]: builder.query({ query: () => ({ url: "/firsttimesetup/", @@ -268,6 +276,7 @@ export const { useFetchIncompleteFacesQuery, useLoginMutation, useSignUpMutation, + useLogoutMutation, useWorkerQuery, useDeleteUserMutation, useManageUpdateUserMutation, diff --git a/src/components/menubars/TopMenu.tsx b/src/components/menubars/TopMenu.tsx index 243c4ea0..1f534c49 100644 --- a/src/components/menubars/TopMenu.tsx +++ b/src/components/menubars/TopMenu.tsx @@ -13,8 +13,8 @@ import { push } from "redux-first-history"; import { toggleSidebar } from "../../actions/uiActions"; import { api } from "../../api_client/api"; +import { useLogoutMutation } from "../../api_client/api"; import { serverAddress } from "../../api_client/apiClient"; -import { logout } from "../../store/auth/authSlice"; import { useAppDispatch, useAppSelector } from "../../store/store"; import { ChunkedUploadButton } from "../ChunkedUploadButton"; import { CustomSearch } from "../CustomSearch"; @@ -27,6 +27,7 @@ export function TopMenu() { const userSelfDetails = useAppSelector(state => state.user.userSelfDetails); const { t } = useTranslation(); const matches = useMediaQuery("(min-width: 700px)"); + const [logout] = useLogoutMutation(); useEffect(() => { if (auth.access) { @@ -90,7 +91,7 @@ export function TopMenu() { } onClick={() => { - dispatch(logout()); + logout(); dispatch(api.util.resetApiState()); }} > diff --git a/src/store/auth/authSlice.ts b/src/store/auth/authSlice.ts index 051cfcb6..011fd501 100644 --- a/src/store/auth/authSlice.ts +++ b/src/store/auth/authSlice.ts @@ -32,14 +32,6 @@ const authSlice = createSlice({ token: payload.access, }, }), - logout: () => { - cookies.remove("access"); - cookies.remove("refresh"); - cookies.remove("csrftoken"); - cookies.remove("jwt"); - push("/login"); - return initialState; - }, clearError: state => ({ ...state, error: null }), }, extraReducers: builder => { @@ -64,11 +56,17 @@ const authSlice = createSlice({ access: null, refresh: null, error: AuthErrorSchema.parse(payload), - })); + })) + .addMatcher(api.endpoints.logout.matchFulfilled, state => { + cookies.remove("access"); + cookies.remove("refresh"); + push("/login"); + return { access: null, refresh: null, error: null }; + }); }, }); export const authReducer = authSlice.reducer; export const { actions: authActions } = authSlice; -export const { logout, tokenReceived, clearError } = authActions; +export const { tokenReceived, clearError } = authActions; diff --git a/src/store/middleware/errorMiddleware.ts b/src/store/middleware/errorMiddleware.ts index dfea31d7..40d51e18 100644 --- a/src/store/middleware/errorMiddleware.ts +++ b/src/store/middleware/errorMiddleware.ts @@ -4,7 +4,6 @@ import { isRejectedWithValue } from "@reduxjs/toolkit"; import { Endpoints, api } from "../../api_client/api"; import { notification } from "../../service/notifications"; import { AuthErrorSchema } from "../auth/auth.zod"; -import { logout } from "../auth/authSlice"; export const errorMiddleware: Middleware = ({ dispatch }: MiddlewareAPI) => @@ -19,8 +18,7 @@ export const errorMiddleware: Middleware = if (error.field === "code") { if (error.message === "token_not_valid") { notification.invalidToken(); - dispatch(logout()); - dispatch(api.util.resetApiState()); + dispatch(api.endpoints.logout.initiate()); return; } }