mirror of
https://github.com/TheRealOwenRees/chess-scribe-website.git
synced 2026-07-23 01:46:57 +00:00
basic loading of user's studies
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
import { useLichessUser } from "#/context/LichessUserContext.tsx";
|
import { useLichessUser } from "#/context/LichessUserContext.tsx";
|
||||||
import { useLichessOAuth } from "#/hooks/useLichessOAuth.ts";
|
import { useLichess } from "#/hooks/useLichess.ts";
|
||||||
|
|
||||||
const LichessButton = () => {
|
const LichessButton = () => {
|
||||||
const { lichessLogin, lichessLogout } = useLichessOAuth();
|
const { lichessLogin, lichessLogout } = useLichess();
|
||||||
const { user } = useLichessUser();
|
const { user } = useLichessUser();
|
||||||
|
|
||||||
const onClickHandler = () => {
|
const onClickHandler = () => {
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
const LichessStudyUrlInput = () => {
|
||||||
|
return <input placeholder="Lichess Study URL" className="" />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LichessStudyUrlInput;
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { useLichess } from "#/hooks/useLichess.ts";
|
||||||
|
|
||||||
|
const SelectLichessStudy = () => {
|
||||||
|
const { getLichessUserStudies } = useLichess();
|
||||||
|
|
||||||
|
const onClickHandler = async () => {
|
||||||
|
await getLichessUserStudies();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-secondary"
|
||||||
|
onClick={onClickHandler}
|
||||||
|
>
|
||||||
|
Select Lichess Study
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SelectLichessStudy;
|
||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
getSession,
|
getSession,
|
||||||
getToken,
|
getToken,
|
||||||
getUser,
|
getUser,
|
||||||
|
getUserStudies,
|
||||||
login,
|
login,
|
||||||
logout,
|
logout,
|
||||||
setSession,
|
setSession,
|
||||||
@@ -17,8 +18,8 @@ interface ITokenData {
|
|||||||
token_type: string;
|
token_type: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useLichessOAuth = () => {
|
export const useLichess = () => {
|
||||||
const { setUser } = useLichessUser();
|
const { user, setUser } = useLichessUser();
|
||||||
|
|
||||||
const loginFn = useServerFn(login);
|
const loginFn = useServerFn(login);
|
||||||
const logoutFn = useServerFn(logout);
|
const logoutFn = useServerFn(logout);
|
||||||
@@ -26,6 +27,7 @@ export const useLichessOAuth = () => {
|
|||||||
const getUserFn = useServerFn(getUser);
|
const getUserFn = useServerFn(getUser);
|
||||||
const setSessionFn = useServerFn(setSession);
|
const setSessionFn = useServerFn(setSession);
|
||||||
const getSessionFn = useServerFn(getSession);
|
const getSessionFn = useServerFn(getSession);
|
||||||
|
const getUserStudiesFn = useServerFn(getUserStudies);
|
||||||
|
|
||||||
const lichessAccessToken = async ({ code }: { code: string }) => {
|
const lichessAccessToken = async ({ code }: { code: string }) => {
|
||||||
return accessTokenFn({ data: { code } });
|
return accessTokenFn({ data: { code } });
|
||||||
@@ -34,11 +36,13 @@ export const useLichessOAuth = () => {
|
|||||||
const setLichessUser = async ({
|
const setLichessUser = async ({
|
||||||
username,
|
username,
|
||||||
id,
|
id,
|
||||||
|
token,
|
||||||
}: {
|
}: {
|
||||||
username: string;
|
username: string;
|
||||||
id: string;
|
id: string;
|
||||||
|
token: string;
|
||||||
}) => {
|
}) => {
|
||||||
await setSessionFn({ data: { username, id } });
|
await setSessionFn({ data: { username, id, token } });
|
||||||
setUser({ username, id, isLoggedIn: true });
|
setUser({ username, id, isLoggedIn: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -48,9 +52,7 @@ export const useLichessOAuth = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const lichessLogin = async () => {
|
const lichessLogin = async () => await loginFn();
|
||||||
await loginFn();
|
|
||||||
};
|
|
||||||
|
|
||||||
const lichessLogout = async () => {
|
const lichessLogout = async () => {
|
||||||
await logoutFn();
|
await logoutFn();
|
||||||
@@ -70,12 +72,22 @@ export const useLichessOAuth = () => {
|
|||||||
(async () => {
|
(async () => {
|
||||||
const tokenData = await lichessAccessToken({ code });
|
const tokenData = await lichessAccessToken({ code });
|
||||||
const userData = await getLichessUser({ tokenData });
|
const userData = await getLichessUser({ tokenData });
|
||||||
await setLichessUser({ username: userData.username, id: userData.id });
|
|
||||||
|
await setLichessUser({
|
||||||
|
username: userData.username,
|
||||||
|
id: userData.id,
|
||||||
|
token: tokenData.access_token,
|
||||||
|
});
|
||||||
await navigate({ to: "/chessboard" });
|
await navigate({ to: "/chessboard" });
|
||||||
})();
|
})();
|
||||||
}, [navigate, code]);
|
}, [navigate, code]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getLichessUserStudies = async () => {
|
||||||
|
if (!user) throw new Error("User not found");
|
||||||
|
await getUserStudiesFn();
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
lichessLogin,
|
lichessLogin,
|
||||||
lichessLogout,
|
lichessLogout,
|
||||||
@@ -84,5 +96,6 @@ export const useLichessOAuth = () => {
|
|||||||
setLichessUser,
|
setLichessUser,
|
||||||
getLichessSession,
|
getLichessSession,
|
||||||
useLichessCallback,
|
useLichessCallback,
|
||||||
|
getLichessUserStudies,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
import { getRouteApi } from "@tanstack/react-router";
|
import { getRouteApi } from "@tanstack/react-router";
|
||||||
import { useLichessOAuth } from "#/hooks/useLichessOAuth.ts";
|
import { useLichess } from "#/hooks/useLichess.ts";
|
||||||
|
|
||||||
const routeApi = getRouteApi("/callback");
|
const routeApi = getRouteApi("/callback");
|
||||||
|
|
||||||
const Callback = () => {
|
const Callback = () => {
|
||||||
const { useLichessCallback } = useLichessOAuth();
|
const { useLichessCallback } = useLichess();
|
||||||
const { code } = routeApi.useSearch();
|
const { code } = routeApi.useSearch();
|
||||||
useLichessCallback({ code }).then();
|
useLichessCallback({ code }).then();
|
||||||
|
|
||||||
return <div>{code}</div>;
|
return <div>Loading...</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Callback;
|
export default Callback;
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ import { lazy, Suspense } from "react";
|
|||||||
import CustomHeaders from "#/components/CustomHeaders.tsx";
|
import CustomHeaders from "#/components/CustomHeaders.tsx";
|
||||||
import HeaderFields from "#/components/HeaderFields.tsx";
|
import HeaderFields from "#/components/HeaderFields.tsx";
|
||||||
import LichessButton from "#/components/LichessButton.tsx";
|
import LichessButton from "#/components/LichessButton.tsx";
|
||||||
|
import LichessStudyUrlInput from "#/components/LichessStudyUrlInput.tsx";
|
||||||
import Section from "#/components/Section.tsx";
|
import Section from "#/components/Section.tsx";
|
||||||
|
import SelectLichessStudy from "#/components/SelectLichessStudy.tsx";
|
||||||
import { useChessGame } from "#/hooks/useChessGame.ts";
|
import { useChessGame } from "#/hooks/useChessGame.ts";
|
||||||
|
|
||||||
const PgnViewer = lazy(() => import("#/components/PgnViewer.tsx"));
|
const PgnViewer = lazy(() => import("#/components/PgnViewer.tsx"));
|
||||||
@@ -44,6 +46,7 @@ const Chessboard = () => {
|
|||||||
className="file-input max-w-xs"
|
className="file-input max-w-xs"
|
||||||
onChange={handleLoadPgn}
|
onChange={handleLoadPgn}
|
||||||
/>
|
/>
|
||||||
|
<SelectLichessStudy /> or <LichessStudyUrlInput />
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
<div className="grid lg:grid-cols-2 gap-4">
|
<div className="grid lg:grid-cols-2 gap-4">
|
||||||
|
|||||||
+57
-4
@@ -22,7 +22,11 @@ export const getSession = createServerFn({ method: "GET" }).handler(
|
|||||||
const session = getCookie("lichess-session");
|
const session = getCookie("lichess-session");
|
||||||
if (!session) return null;
|
if (!session) return null;
|
||||||
try {
|
try {
|
||||||
return JSON.parse(session) as { username: string; id: string };
|
return JSON.parse(session) as {
|
||||||
|
username: string;
|
||||||
|
id: string;
|
||||||
|
token: string;
|
||||||
|
};
|
||||||
} catch {
|
} catch {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -30,11 +34,17 @@ export const getSession = createServerFn({ method: "GET" }).handler(
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const setSession = createServerFn({ method: "POST" })
|
export const setSession = createServerFn({ method: "POST" })
|
||||||
.inputValidator((data: { username: string; id: string }) => data)
|
.inputValidator(
|
||||||
|
(data: { username: string; id: string; token: string }) => data,
|
||||||
|
)
|
||||||
.handler(async ({ data }) => {
|
.handler(async ({ data }) => {
|
||||||
setCookie(
|
setCookie(
|
||||||
"lichess-session",
|
"lichess-session",
|
||||||
JSON.stringify({ username: data.username, id: data.id }),
|
JSON.stringify({
|
||||||
|
username: data.username,
|
||||||
|
id: data.id,
|
||||||
|
token: data.token,
|
||||||
|
}),
|
||||||
{
|
{
|
||||||
path: "/",
|
path: "/",
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
@@ -86,6 +96,8 @@ export const getToken = createServerFn({ method: "POST" })
|
|||||||
export const getUser = createServerFn({ method: "GET" })
|
export const getUser = createServerFn({ method: "GET" })
|
||||||
.inputValidator((data: { access_token: string }) => data)
|
.inputValidator((data: { access_token: string }) => data)
|
||||||
.handler(async ({ data }) => {
|
.handler(async ({ data }) => {
|
||||||
|
console.log(data.access_token);
|
||||||
|
|
||||||
const response = await fetch("https://lichess.org/api/account", {
|
const response = await fetch("https://lichess.org/api/account", {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${data.access_token}`,
|
Authorization: `Bearer ${data.access_token}`,
|
||||||
@@ -95,9 +107,26 @@ export const getUser = createServerFn({ method: "GET" })
|
|||||||
return response.json();
|
return response.json();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const deleteAccessToken = createServerFn().handler(async () => {
|
||||||
|
const session = await getSession();
|
||||||
|
const token = session?.token;
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
const response = await fetch("https://lichess.org/api/token", {
|
||||||
|
method: "DELETE",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return await response.json();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export const logout = createServerFn().handler(async () => {
|
export const logout = createServerFn().handler(async () => {
|
||||||
|
await deleteAccessToken();
|
||||||
deleteCookie("lichess-session", { path: "/" });
|
deleteCookie("lichess-session", { path: "/" });
|
||||||
deleteCookie("lichess-oauth-verifier", { path: "/" });
|
deleteCookie("lichess-oauth-verifier", { path: "/" }); // cookie shouldn't exist
|
||||||
});
|
});
|
||||||
|
|
||||||
export const login = createServerFn({ method: "GET" }).handler(async () => {
|
export const login = createServerFn({ method: "GET" }).handler(async () => {
|
||||||
@@ -125,3 +154,27 @@ export const login = createServerFn({ method: "GET" }).handler(async () => {
|
|||||||
href: `https://lichess.org/oauth?${params.toString()}`,
|
href: `https://lichess.org/oauth?${params.toString()}`,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const getUserStudies = createServerFn({ method: "POST" }).handler(
|
||||||
|
async () => {
|
||||||
|
const session = await getSession();
|
||||||
|
|
||||||
|
if (!session) return;
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
`https://lichess.org/api/study/by/${session.username}`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${session.token}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const studies = await response.text();
|
||||||
|
|
||||||
|
return studies
|
||||||
|
.trim()
|
||||||
|
.split("\n")
|
||||||
|
.map((study) => JSON.parse(study));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user