diff --git a/apps/cyberstorm-remix/app/c/community.tsx b/apps/cyberstorm-remix/app/c/community.tsx index ac9aca8cd..e5b10e85d 100644 --- a/apps/cyberstorm-remix/app/c/community.tsx +++ b/apps/cyberstorm-remix/app/c/community.tsx @@ -7,7 +7,7 @@ import { NewLink, } from "@thunderstore/cyberstorm"; import "./Community.css"; -import { getDapper } from "cyberstorm/dapper/sessionUtils"; +// import { getDapper } from "cyberstorm/dapper/sessionUtils"; import { PackageSearch } from "~/commonComponents/PackageSearch/PackageSearch"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faBook } from "@fortawesome/free-solid-svg-icons"; @@ -16,6 +16,7 @@ import { ApiError } from "@thunderstore/thunderstore-api"; import { PackageOrderOptions } from "~/commonComponents/PackageSearch/PackageOrder"; import { faArrowUpRight } from "@fortawesome/pro-solid-svg-icons"; import { PageHeader } from "~/commonComponents/PageHeader/PageHeader"; +import { DapperTs } from "@thunderstore/dapper-ts"; export const meta: MetaFunction = ({ data }) => { return [ @@ -27,7 +28,11 @@ export const meta: MetaFunction = ({ data }) => { export async function loader({ request, params }: LoaderFunctionArgs) { if (params.communityId) { try { - const dapper = await getDapper(); + const dapper = new DapperTs({ + apiHost: process.env.PUBLIC_API_URL, + sessionId: undefined, + csrfToken: undefined, + }); const searchParams = new URL(request.url).searchParams; const ordering = searchParams.get("ordering") ?? PackageOrderOptions.Updated; @@ -79,7 +84,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) { export async function clientLoader({ request, params }: LoaderFunctionArgs) { if (params.communityId) { try { - const dapper = await getDapper(true); + const dapper = window.Dapper; const searchParams = new URL(request.url).searchParams; const ordering = searchParams.get("ordering") ?? PackageOrderOptions.Updated; diff --git a/apps/cyberstorm-remix/app/communities/communities.tsx b/apps/cyberstorm-remix/app/communities/communities.tsx index 309c56e66..196661077 100644 --- a/apps/cyberstorm-remix/app/communities/communities.tsx +++ b/apps/cyberstorm-remix/app/communities/communities.tsx @@ -26,8 +26,9 @@ import { useSearchParams, } from "@remix-run/react"; import { Communities } from "@thunderstore/dapper/types"; -import { getDapper } from "cyberstorm/dapper/sessionUtils"; +// import { getDapper } from "cyberstorm/dapper/sessionUtils"; import { PageHeader } from "~/commonComponents/PageHeader/PageHeader"; +import { DapperTs } from "@thunderstore/dapper-ts"; export const meta: MetaFunction = () => { return [ @@ -69,7 +70,11 @@ export async function loader({ request }: LoaderFunctionArgs) { const order = searchParams.get("order") ?? SortOptions.Popular; const search = searchParams.get("search"); const page = undefined; - const dapper = await getDapper(); + const dapper = new DapperTs({ + apiHost: process.env.PUBLIC_API_URL, + sessionId: undefined, + csrfToken: undefined, + }); return await dapper.getCommunities(page, order ?? "", search ?? ""); // REMIX TODO: Add sentry and try except so, that we get a proper error page // throw new Response("Community not found", { status: 404 }); @@ -80,7 +85,7 @@ export async function clientLoader({ request }: LoaderFunctionArgs) { const order = searchParams.get("order") ?? SortOptions.Popular; const search = searchParams.get("search"); const page = undefined; - const dapper = await getDapper(true); + const dapper = window.Dapper; return await dapper.getCommunities(page, order ?? "", search ?? ""); // REMIX TODO: Add sentry and try except so, that we get a proper error page // throw new Response("Community not found", { status: 404 }); diff --git a/apps/cyberstorm-remix/app/p/packageListing.tsx b/apps/cyberstorm-remix/app/p/packageListing.tsx index aa3500799..d77d9147e 100644 --- a/apps/cyberstorm-remix/app/p/packageListing.tsx +++ b/apps/cyberstorm-remix/app/p/packageListing.tsx @@ -3,14 +3,14 @@ import { Outlet, useLoaderData, useLocation, + useOutletContext, useRevalidator, } from "@remix-run/react"; import { - Button, CopyButton, - Dialog, Heading, Image, + Modal, NewBreadCrumbs, NewButton, NewIcon, @@ -19,7 +19,6 @@ import { Tabs, } from "@thunderstore/cyberstorm"; import "./packageListing.css"; -import { getDapper } from "cyberstorm/dapper/sessionUtils"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { ApiError } from "@thunderstore/thunderstore-api"; import { ThunderstoreLogo } from "@thunderstore/cyberstorm/src/svg/svg"; @@ -33,7 +32,7 @@ import { faThumbTack, } from "@fortawesome/free-solid-svg-icons"; import TeamMembers from "./components/TeamMembers/TeamMembers"; -import { ReactNode, useEffect, useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { useHydrated } from "remix-utils/use-hydrated"; import { PackageDeprecateAction, @@ -51,6 +50,8 @@ import { formatFileSize, formatInteger, } from "@thunderstore/cyberstorm/src/utils/utils"; +import { DapperTs } from "@thunderstore/dapper-ts"; +import { OutletContextShape } from "~/root"; export const meta: MetaFunction = ({ data }) => { return [ @@ -62,7 +63,11 @@ export const meta: MetaFunction = ({ data }) => { export async function loader({ params }: LoaderFunctionArgs) { if (params.communityId && params.namespaceId && params.packageId) { try { - const dapper = await getDapper(); + const dapper = new DapperTs({ + apiHost: process.env.PUBLIC_API_URL, + sessionId: undefined, + csrfToken: undefined, + }); return { community: await dapper.getCommunity(params.communityId), communityFilters: await dapper.getCommunityFilters(params.communityId), @@ -72,7 +77,6 @@ export async function loader({ params }: LoaderFunctionArgs) { params.packageId ), team: await dapper.getTeamDetails(params.namespaceId), - currentUser: await dapper.getCurrentUser(), }; } catch (error) { if (error instanceof ApiError) { @@ -86,44 +90,69 @@ export async function loader({ params }: LoaderFunctionArgs) { throw new Response("Package not found", { status: 404 }); } -export async function clientLoader({ params }: LoaderFunctionArgs) { - if (params.communityId && params.namespaceId && params.packageId) { - try { - const dapper = await getDapper(true); - return { - community: await dapper.getCommunity(params.communityId), - communityFilters: await dapper.getCommunityFilters(params.communityId), - listing: await dapper.getPackageListingDetails( - params.communityId, - params.namespaceId, - params.packageId - ), - team: await dapper.getTeamDetails(params.namespaceId), - currentUser: await dapper.getCurrentUser(), - }; - } catch (error) { - if (error instanceof ApiError) { - throw new Response("Package not found", { status: 404 }); - } else { - // REMIX TODO: Add sentry - throw error; - } - } - } - throw new Response("Package not found", { status: 404 }); -} +// export async function clientLoader({ params }: LoaderFunctionArgs) { +// if (params.communityId && params.namespaceId && params.packageId) { +// try { +// const dapper = window.Dapper; +// return { +// community: await dapper.getCommunity(params.communityId), +// communityFilters: await dapper.getCommunityFilters(params.communityId), +// listing: await dapper.getPackageListingDetails( +// params.communityId, +// params.namespaceId, +// params.packageId +// ), +// team: await dapper.getTeamDetails(params.namespaceId), +// currentUser: await dapper.getCurrentUser(), +// }; +// } catch (error) { +// if (error instanceof ApiError) { +// throw new Response("Package not found", { status: 404 }); +// } else { +// // REMIX TODO: Add sentry +// throw error; +// } +// } +// } +// throw new Response("Package not found", { status: 404 }); +// } export default function Community() { - const { community, communityFilters, listing, team, currentUser } = - useLoaderData(); - const revalidator = useRevalidator(); + const { community, communityFilters, listing, team } = + useLoaderData(); + const location = useLocation(); - const rpc = currentUser.rated_packages_cyberstorm as string[]; - const [isLiked, setIsLiked] = useState( - rpc.includes(`${listing.namespace}-${listing.name}`) - ); - const [isRefetching, setIsRefetching] = useState(false); + const outletContext = useOutletContext() as OutletContextShape; + const currentUser = outletContext.currentUser; + const config = outletContext.requestConfig; + + const [isLiked, setIsLiked] = useState(false); + + // TODO: VERY CRITICAL TO FIGURE OUT !!! Figure out if this is stupid or not? I'm not sure if Remix will let fetch part of the client loader. + // Ideally we could just tell Remix to use the clientLoader to fetch all related data, but it seems like it just doesnt do it, so we have to do this. + const fetchAndSetRatedPackages = async () => { + const dapper = window.Dapper; + if (currentUser?.username) { + const rp = await dapper.getRatedPackages(); + setIsLiked( + rp.rated_packages.includes(`${listing.namespace}-${listing.name}`) + ); + } + }; + + const revalidator = useRevalidator(); + + const revalidateLoaderData = async () => { + if (revalidator.state === "idle") { + revalidator.revalidate(); + } + }; + + useEffect(() => { + fetchAndSetRatedPackages(); + }, []); + const isHydrated = useHydrated(); const startsHydrated = useRef(isHydrated); @@ -149,64 +178,6 @@ export default function Community() { }, []); // END: For sidebar meta dates - useEffect(() => { - if (!startsHydrated.current && isHydrated) return; - if ( - currentUser.rated_packages_cyberstorm.length > 0 && - typeof currentUser.rated_packages_cyberstorm[0] === "string" - ) { - const rpc = currentUser.rated_packages_cyberstorm as string[]; - setIsLiked(rpc.includes(`${listing.namespace}-${listing.name}`)); - } - setIsRefetching(false); - }, [currentUser]); - - // REMIX TODO: Move current user to stand-alone loader and revalidate only currentUser - async function useUpdateLikeStatus() { - if (!isRefetching) { - setIsRefetching(true); - revalidator.revalidate(); - } - } - - // REMIX TODO: Move current user to stand-alone loader and revalidate only currentUser - async function useUpdatePackageData() { - if (!isRefetching) { - setIsRefetching(true); - revalidator.revalidate(); - } - } - - // // Header helpers - // const packageDetailsMeta = [ - // - // - // - // - // - // {listing.namespace} - // - // , - // ]; - - // if (listing.website_url) { - // packageDetailsMeta.push( - // - // - // {listing.website_url} - // - // - // - // - // - // ); - // } - // Sidebar helpers const mappedPackageTagList = listing.categories.map((category) => { return ( @@ -228,59 +199,53 @@ export default function Community() { ? "source" : "details"; - const updateTimeDelta = Math.round( - (Date.now() - Date.parse(listing.last_updated)) / 86400000 + const managementTools = ( + + + + + Manage + + } + > + { + return { label: cat.name, value: cat.slug }; + })} + community={listing.community_identifier} + namespace={listing.namespace} + package={listing.name} + current_categories={listing.categories} + isDeprecated={listing.is_deprecated} + dataUpdateTrigger={revalidateLoaderData} + deprecationButton={ + + {listing.is_deprecated ? "Undeprecate" : "Deprecate"} + + } + config={config} + /> + ); - const isNew = updateTimeDelta < 3; - if ( - !listing.is_pinned && - !listing.is_nsfw && - !listing.is_deprecated && - !isNew - ) { - return null; - } - const flagList: ReactNode[] = []; - if (listing.is_pinned) { - flagList.push( - - - - - Pinned - - ); - } - if (listing.is_deprecated) { - flagList.push( - - - - - Deprecated - - ); - } - if (listing.is_nsfw) { - flagList.push( - - - - - NSFW - - ); - } - if (isNew) { - flagList.push( - - - - - New - - ); - } return ( <> @@ -368,69 +333,12 @@ export default function Community() { } />
- {/* - - - - - - Install - - - */} {/* TODO: Admin tools */} - {currentUser.teams.some(function (cuTeam) { + {currentUser?.teams.some(function (cuTeam) { return cuTeam?.name === listing.team.name; - }) ? ( - - - - - Manage - - } - > - {/* package management */} - { - return { label: cat.name, value: cat.slug }; - })} - community={listing.community_identifier} - namespace={listing.namespace} - package={listing.name} - current_categories={listing.categories} - isDeprecated={listing.is_deprecated} - packageDataUpdateTrigger={useUpdatePackageData} - deprecationButton={ - - {listing.is_deprecated ? ( - Undeprecate - ) : ( - Deprecate - )} - - } - /> - - ) : null} + }) + ? managementTools + : null}
@@ -566,15 +474,16 @@ export default function Community() { {/* */} @@ -667,7 +576,44 @@ export default function Community() { {mappedPackageTagList}
- {flagList} + {listing.is_pinned ? ( + + + + + Pinned + + ) : null} + {listing.is_deprecated ? ( + + + + + Deprecated + + ) : null} + {listing.is_nsfw ? ( + + + + + NSFW + + ) : null} + {Math.round( + (Date.now() - Date.parse(listing.last_updated)) / 86400000 + ) < 3 ? ( + + + + + New + + ) : null}
diff --git a/apps/cyberstorm-remix/app/p/tabs/Changelog/Changelog.tsx b/apps/cyberstorm-remix/app/p/tabs/Changelog/Changelog.tsx index 2eaf7e410..f91931621 100644 --- a/apps/cyberstorm-remix/app/p/tabs/Changelog/Changelog.tsx +++ b/apps/cyberstorm-remix/app/p/tabs/Changelog/Changelog.tsx @@ -1,13 +1,18 @@ import styles from "../../../Markdown.module.css"; -import { getDapper } from "cyberstorm/dapper/sessionUtils"; +// import { getDapper } from "cyberstorm/dapper/sessionUtils"; import { ApiError } from "@thunderstore/thunderstore-api"; import { useLoaderData } from "@remix-run/react"; import { LoaderFunctionArgs } from "@remix-run/node"; +import { DapperTs } from "@thunderstore/dapper-ts"; export async function loader({ params }: LoaderFunctionArgs) { if (params.namespaceId && params.packageId) { try { - const dapper = await getDapper(); + const dapper = new DapperTs({ + apiHost: process.env.PUBLIC_API_URL, + sessionId: undefined, + csrfToken: undefined, + }); return { status: "ok", message: "", @@ -39,7 +44,7 @@ export async function loader({ params }: LoaderFunctionArgs) { export async function clientLoader({ params }: LoaderFunctionArgs) { if (params.namespaceId && params.packageId) { try { - const dapper = await getDapper(true); + const dapper = window.Dapper; return { status: "ok", message: "", diff --git a/apps/cyberstorm-remix/app/p/tabs/Readme/Readme.tsx b/apps/cyberstorm-remix/app/p/tabs/Readme/Readme.tsx index bdbdc7f7a..2b6cd83b2 100644 --- a/apps/cyberstorm-remix/app/p/tabs/Readme/Readme.tsx +++ b/apps/cyberstorm-remix/app/p/tabs/Readme/Readme.tsx @@ -1,13 +1,18 @@ import { LoaderFunctionArgs } from "@remix-run/node"; -import { getDapper } from "cyberstorm/dapper/sessionUtils"; +// import { getDapper } from "cyberstorm/dapper/sessionUtils"; import styles from "../../../Markdown.module.css"; import { ApiError } from "@thunderstore/thunderstore-api"; import { useLoaderData } from "@remix-run/react"; +import { DapperTs } from "@thunderstore/dapper-ts"; export async function loader({ params }: LoaderFunctionArgs) { if (params.namespaceId && params.packageId) { try { - const dapper = await getDapper(); + const dapper = new DapperTs({ + apiHost: process.env.PUBLIC_API_URL, + sessionId: undefined, + csrfToken: undefined, + }); return { status: "ok", message: "", @@ -39,7 +44,7 @@ export async function loader({ params }: LoaderFunctionArgs) { export async function clientLoader({ params }: LoaderFunctionArgs) { if (params.namespaceId && params.packageId) { try { - const dapper = await getDapper(true); + const dapper = window.Dapper; return { status: "ok", message: "", diff --git a/apps/cyberstorm-remix/app/p/tabs/Required/Required.tsx b/apps/cyberstorm-remix/app/p/tabs/Required/Required.tsx index 38a0c0ccb..0fd987da6 100644 --- a/apps/cyberstorm-remix/app/p/tabs/Required/Required.tsx +++ b/apps/cyberstorm-remix/app/p/tabs/Required/Required.tsx @@ -1,15 +1,20 @@ import "./Required.css"; import { Heading } from "@thunderstore/cyberstorm"; import { LoaderFunctionArgs } from "@remix-run/node"; -import { getDapper } from "cyberstorm/dapper/sessionUtils"; +// import { getDapper } from "cyberstorm/dapper/sessionUtils"; import { ApiError } from "@thunderstore/thunderstore-api"; import { useLoaderData } from "@remix-run/react"; import { ListingDependency } from "~/commonComponents/ListingDependency/ListingDependency"; +import { DapperTs } from "@thunderstore/dapper-ts"; export async function loader({ params }: LoaderFunctionArgs) { if (params.communityId && params.namespaceId && params.packageId) { try { - const dapper = await getDapper(); + const dapper = new DapperTs({ + apiHost: process.env.PUBLIC_API_URL, + sessionId: undefined, + csrfToken: undefined, + }); return { listing: await dapper.getPackageListingDetails( params.communityId, @@ -32,7 +37,7 @@ export async function loader({ params }: LoaderFunctionArgs) { export async function clientLoader({ params }: LoaderFunctionArgs) { if (params.communityId && params.namespaceId && params.packageId) { try { - const dapper = await getDapper(true); + const dapper = window.Dapper; return { listing: await dapper.getPackageListingDetails( params.communityId, diff --git a/apps/cyberstorm-remix/app/p/tabs/Versions/Versions.tsx b/apps/cyberstorm-remix/app/p/tabs/Versions/Versions.tsx index febadeffc..2be400d78 100644 --- a/apps/cyberstorm-remix/app/p/tabs/Versions/Versions.tsx +++ b/apps/cyberstorm-remix/app/p/tabs/Versions/Versions.tsx @@ -14,15 +14,20 @@ import { NewAlert, } from "@thunderstore/cyberstorm"; import { LoaderFunctionArgs } from "@remix-run/node"; -import { getDapper } from "cyberstorm/dapper/sessionUtils"; +// import { getDapper } from "cyberstorm/dapper/sessionUtils"; import { ApiError } from "@thunderstore/thunderstore-api"; import { useLoaderData } from "@remix-run/react"; import { versionsSchema } from "@thunderstore/dapper-ts/src/methods/package"; +import { DapperTs } from "@thunderstore/dapper-ts"; export async function loader({ params }: LoaderFunctionArgs) { if (params.namespaceId && params.packageId) { try { - const dapper = await getDapper(); + const dapper = new DapperTs({ + apiHost: process.env.PUBLIC_API_URL, + sessionId: undefined, + csrfToken: undefined, + }); return { status: "ok", message: "", @@ -54,7 +59,7 @@ export async function loader({ params }: LoaderFunctionArgs) { export async function clientLoader({ params }: LoaderFunctionArgs) { if (params.namespaceId && params.packageId) { try { - const dapper = await getDapper(true); + const dapper = window.Dapper; return { status: "ok", message: "", diff --git a/apps/cyberstorm-remix/app/root.tsx b/apps/cyberstorm-remix/app/root.tsx index fcc0d72fa..d96b339c5 100644 --- a/apps/cyberstorm-remix/app/root.tsx +++ b/apps/cyberstorm-remix/app/root.tsx @@ -9,23 +9,18 @@ import { Scripts, // ScrollRestoration, isRouteErrorResponse, - useLoaderData, + redirect, useLocation, useRouteError, + useRouteLoaderData, } from "@remix-run/react"; // import { LinksFunction } from "@remix-run/react/dist/routeModules"; import { Provider as RadixTooltip } from "@radix-ui/react-tooltip"; -import { - MobileNavigationMenu, - MobileUserPopoverContent, - Navigation, -} from "cyberstorm/navigation/Navigation"; import { LinkLibrary } from "cyberstorm/utils/LinkLibrary"; import { AdContainer, LinkingProvider } from "@thunderstore/cyberstorm"; import { DapperTs } from "@thunderstore/dapper-ts"; -// import { CurrentUser } from "@thunderstore/dapper/types"; -// import { getDapper } from "cyberstorm/dapper/sessionUtils"; +import { CurrentUser } from "@thunderstore/dapper/types"; import { captureRemixErrorBoundaryError, withSentry } from "@sentry/remix"; import { @@ -35,11 +30,10 @@ import { import { useEffect, useRef, useState } from "react"; import { useHydrated } from "remix-utils/use-hydrated"; import Toast from "@thunderstore/cyberstorm/src/components/Toast"; -import { SessionProvider } from "@thunderstore/ts-api-react"; -import { CurrentUser } from "@thunderstore/dapper/types"; +import { SessionProvider, useSession } from "@thunderstore/ts-api-react"; import { Footer } from "./commonComponents/Footer/Footer"; -// Disabled until we have "rated_packages_cyberstorm" available in the currentUser django endpoint -// import { getDapper } from "cyberstorm/dapper/sessionUtils"; +import { NavigationWrapper } from "cyberstorm/navigation/NavigationWrapper"; +import { RequestConfig } from "@thunderstore/thunderstore-api"; // REMIX TODO: https://remix.run/docs/en/main/route/links // export const links: LinksFunction = () => [{ rel: "stylesheet", href: styles }]; @@ -71,6 +65,11 @@ declare global { } } +export type OutletContextShape = { + currentUser: CurrentUser | undefined; + requestConfig: RequestConfig; +}; + export const meta: MetaFunction = () => { return [ { title: "Thunderstore" }, @@ -95,34 +94,16 @@ export async function loader() { }; } -// export async function clientLoader() { -// const dapper = await getDapper(true); - -// return { -// envStuff: { -// ENV: getPublicEnvVariables([ -// "PUBLIC_API_URL", -// "PUBLIC_CLIENT_SENTRY_DSN", -// "PUBLIC_SITE_URL", -// ]), -// }, -// currentUser: await dapper.getCurrentUser(), -// }; -// } - export function shouldRevalidate() { return false; } const adContainerIds = ["right-column-1", "right-column-2", "right-column-3"]; -function Root() { - const loaderOutput = useLoaderData(); - const parsedLoaderOutput: { - envStuff: { - ENV: publicEnvVariables; - }; - } = JSON.parse(JSON.stringify(loaderOutput)); +export function Layout({ children }: { children: React.ReactNode }) { + const data = useRouteLoaderData("root"); + // const error = useRouteError(); + // console.log(error); const location = useLocation(); const shouldShowAds = location.pathname.startsWith("/teams") @@ -135,25 +116,6 @@ function Root() { ? false : true; - const isHydrated = useHydrated(); - const startsHydrated = useRef(isHydrated); - // Disabled until we have "rated_packages_cyberstorm" available in the currentUser django endpoint - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [currentUser, setCurrentUser] = useState(); - - // Disabled until we have "rated_packages_cyberstorm" available in the currentUser django endpoint - // useEffect(() => { - // if (!startsHydrated.current && isHydrated) return; - // const fetchAndSetUser = async () => { - // const dapper = await getDapper(true); - // const fetchedUser = await dapper.getCurrentUser(); - // if (fetchedUser?.username) { - // setCurrentUser(fetchedUser); - // } - // }; - // fetchAndSetUser(); - // }, []); - return ( @@ -184,35 +146,27 @@ function Root() { -