Skip to content

Commit

Permalink
a ton of UPGRADES
Browse files Browse the repository at this point in the history
  • Loading branch information
sphinxrave committed Oct 23, 2024
1 parent 930dcbb commit 0e76d2c
Show file tree
Hide file tree
Showing 15 changed files with 919 additions and 168 deletions.
1 change: 1 addition & 0 deletions packages/react/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useThemeInit } from "./hooks/useTheme";
import { useSyncTFunction } from "./store/i18n";
import { Suspense, useEffect } from "react";
import { routes } from "./routes/router";
import React from "react";

export function App() {
useThemeInit();
Expand Down
5 changes: 4 additions & 1 deletion packages/react/src/Kitchensink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Checkbox } from "./shadcn/ui/checkbox";
export function Kitchensink() {
const [count, setCount] = useState(0);

if (count) throw new Error("Test error");
return (
<div className="space-y-4 p-4">
<h3>This page is for testing components and styling.</h3>
Expand All @@ -27,7 +28,9 @@ export function Kitchensink() {
<h3>Color and variants:</h3>
<div className="flex max-w-5xl flex-row flex-wrap items-start justify-start gap-4">
<Button>Default button</Button>
<Button variant="ghost">Ghost button</Button>
<Button variant="ghost" onClick={() => setCount(count + 1)}>
Ghost button
</Button>
<Button variant="outline">Outline button</Button>
<Button variant="secondary">Secondary button</Button>
<Button variant="link">Link button</Button>
Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/components/about/EmailForm.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useReportMutation } from "@/services/reports.service";
import { useContactReportMutation } from "@/services/reports.service";
import { Button } from "@/shadcn/ui/button";
import {
Form,
Expand Down Expand Up @@ -42,7 +42,7 @@ export function AboutFaqEmailForm() {
},
});

const { mutate } = useReportMutation({ type: "contact" });
const { mutate } = useContactReportMutation();

return (
<Form {...form}>
Expand Down
15 changes: 7 additions & 8 deletions packages/react/src/components/channel/ChannelPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ import {
} from "react-hook-form";
import { useTranslation } from "react-i18next";

const { currentValueAtom, debouncedValueAtom } = atomWithDebounce(
"",
300,
true,
);

interface VtuberPickerProps<
T extends FieldValues,
FieldName extends FieldPath<T>,
Expand All @@ -32,12 +38,6 @@ interface VtuberPickerProps<
onSelect: (value: SearchAutoCompleteChannel) => void;
}

const { currentValueAtom, debouncedValueAtom } = atomWithDebounce(
"",
300,
true,
);

export function ChannelPicker<
T extends FieldValues,
FieldName extends FieldPath<T>,
Expand All @@ -59,8 +59,7 @@ export function ChannelPicker<
<Popover>
<PopoverTrigger asChild>
<Button
className="justify-between border-base-6 px-4 focus:border-blue-6"
size="lg"
className="justify-between border-base-6 pr-2 text-base-11 focus:border-blue-6"
variant="outline"
role="combobox"
>
Expand Down
169 changes: 117 additions & 52 deletions packages/react/src/components/common/ErrorFallback.tsx
Original file line number Diff line number Diff line change
@@ -1,64 +1,129 @@
import { FallbackProps } from "react-error-boundary";
import { Trans, useTranslation } from "react-i18next";
import { TwitterFeed } from "./TwitterFeed";
import { StatusTweetEmbed } from "./TwitterFeed";
import { Button } from "@/shadcn/ui/button";
import { useAuth } from "@/hooks/useAuth";
import {
Card,
CardContent,
CardFooter,
CardHeader,
CardTitle,
} from "@/shadcn/ui/card";
import { Alert, AlertDescription } from "@/shadcn/ui/alert";
import { userAtom, tokenAtom } from "@/store/auth";
import {
Collapsible,
CollapsibleTrigger,
CollapsibleContent,
} from "@/shadcn/ui/collapsible";
import { useSetAtom, useAtom } from "jotai";
import { useState, useCallback } from "react";

export function ErrorFallback({ error }: Partial<FallbackProps>) {
const { t } = useTranslation();
const { logout } = useAuth();
const setUser = useSetAtom(userAtom);
const [token, setToken] = useAtom(tokenAtom);
const [isDebugOpen, setIsDebugOpen] = useState(false);

const logout = useCallback(() => {
setToken(null);
setUser(null);
}, [setToken, setUser]);

return (
<div className="h-full w-full overflow-y-auto p-8">
<div className="mx-auto flex h-full w-full max-w-screen-lg flex-col items-center gap-4">
<h2 className="text-3xl font-bold">{t("component.apiError.title")}</h2>
<p>
<Trans
i18nKey="component.apiError.text"
components={{
twitter: (
<a
className="text-blue-500 underline"
href="https://x.com/holodex"
>
Twitter
</a>
),
discord: (
<a
className="text-blue-500 underline"
href="https://discord.gg/jctkgHBt4b"
>
Discord
</a>
),
}}
/>
</p>
<div className="flex flex-wrap justify-center gap-4">
<Button size="lg" onClick={() => window.location.reload()}>
{t("component.apiError.reload")}
</Button>
<Button
size="lg"
variant="secondary"
onClick={() => {
logout();
window.localStorage.clear();
window.location.assign("/");
}}
<div className="p-4 sm:p-8">
<Card className="mx-auto max-w-2xl bg-base-4">
<CardHeader className="text-center">
<CardTitle className="text-3xl font-bold text-secondary">
{t("component.apiError.title")}
</CardTitle>
</CardHeader>

<CardContent className="space-y-4">
<Alert>
<AlertDescription className="text-center text-base">
<Trans
i18nKey="component.apiError.text"
components={{
twitter: (
<a
key="twitterlink"
className="font-medium text-primary hover:underline"
href="https://x.com/holodex"
target="_blank"
rel="noopener noreferrer"
></a>
),
discord: (
<a
className="font-medium text-primary hover:underline"
href="https://discord.gg/jctkgHBt4b"
target="_blank"
rel="noopener noreferrer"
></a>
),
}}
/>
</AlertDescription>
</Alert>

<div className="flex flex-col gap-4 sm:flex-row sm:justify-center">
<Button
size="lg"
variant="primary"
onClick={() => window.location.reload()}
className="gap-2"
>
<div className="i-lucide:refresh-ccw h-4 w-4" />
{t("component.apiError.reload")}
</Button>
<Button
size="lg"
variant="ghost-secondary"
onClick={() => {
logout();
window.localStorage.clear();
window.location.assign("/");
}}
className="gap-2"
>
<div className="i-lucide:log-out h-4 w-4" />
{t("component.apiError.logoutAndClearCache")}
</Button>
</div>

<Collapsible
open={isDebugOpen}
onOpenChange={setIsDebugOpen}
className=""
>
{t("component.apiError.logoutAndClearCache")}
</Button>
</div>
<code className="max-w-full shrink-0 overflow-x-auto whitespace-pre-wrap rounded-md bg-black/10 px-2 py-0 text-sm">
{error?.message}
</code>
<code className="max-w-full shrink-0 overflow-x-auto whitespace-pre-wrap rounded-md bg-black/10 p-2 text-xs">
{error?.stack}
</code>
<TwitterFeed className="flex h-[400px] w-[min(800px,calc(100vw-40px))] justify-center" />
</div>
<CollapsibleTrigger className="flex w-full items-center justify-between rounded-lg border border-base-6 p-4 font-medium hover:bg-muted">
Debug Information
<div
className={`i-lucide:chevron-down h-4 w-4 transition-transform duration-200 ${
isDebugOpen ? "rotate-180" : ""
}`}
/>
</CollapsibleTrigger>
<CollapsibleContent className="">
<code className="bg-muted/50 my-2 block w-full overflow-x-auto rounded-lg px-4">
{error?.message}
</code>
<code className="bg-muted/50 block w-full overflow-x-auto rounded-lg px-4 text-xs">
{error?.stack}
</code>
</CollapsibleContent>
</Collapsible>

<div className="mx-auto max-w-md">
<StatusTweetEmbed />
</div>
</CardContent>

<CardFooter className="justify-center text-sm text-base-8">
© Holodex
</CardFooter>
</Card>
</div>
);
}
79 changes: 73 additions & 6 deletions packages/react/src/components/common/TwitterFeed.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
import { DetailedHTMLProps, HTMLAttributes, useEffect, useRef } from "react";
import { cn } from "@/lib/utils";
import {
DetailedHTMLProps,
HTMLAttributes,
useEffect,
useRef,
useState,
} from "react";
import { useScript } from "usehooks-ts";

declare global {
// eslint-disable-next-line
var twttr: any;
}

const html = `<a class="twitter-timeline" data-dnt="true" data-height="400" data-width="${Math.min(
window.innerWidth - 40,
800,
)}" href="https://twitter.com/holodex?ref_src=twsrc%5Etfw">Tweets by Holodex</a>`;

export function TwitterFeed(
props: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>,
) {
const ref = useRef<HTMLDivElement>(null);
const status = useScript("https://platform.twitter.com/widgets.js");

const html = `<a class="twitter-timeline" data-dnt="true" data-height="400" data-width="700" href="https://twitter.com/holodex?ref_src=twsrc%5Etfw"></a>`;
useEffect(() => {
if (status === "ready") window.twttr?.widgets.load();
}, [status]);
Expand All @@ -25,3 +28,67 @@ export function TwitterFeed(
<div {...props} ref={ref} dangerouslySetInnerHTML={{ __html: html }} />
);
}

export function StatusTweetEmbed({
...props
}: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>) {
const ref = useRef<HTMLDivElement>(null);
const [tweetUrl, setTweetUrl] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const status = useScript("https://platform.twitter.com/widgets.js");

// Fetch the latest status
useEffect(() => {
fetch("https://ext.holodex.net/api/status")
.then((res) => res.text())
.then((url) => setTweetUrl(url.trim()))
.catch((err) => setError("Failed to load status"));
}, []);

// Create tweet embed when both tweet URL and Twitter script are ready
useEffect(() => {
if (status === "ready" && tweetUrl && window.twttr && ref.current) {
// Clear previous content
ref.current.innerHTML = "";

window.twttr.widgets
.createTweet(
// Extract tweet ID from URL
tweetUrl.split("/").pop()!,
ref.current,
{
theme: "light",
width: 550,
align: "center",
conversation: "none", // Hide replies
},
)
.catch(() => setError("Failed to load tweet"));
}
}, [status, tweetUrl]);

if (error) {
return (
<TwitterFeed className="flex h-[900px] max-w-[min(500px,calc(100vw-40px))] justify-center" />
);
}

// if (!tweetUrl || status !== "ready") {
// return (
// <div {...props} className="p-4 text-gray-500">
// Loading status...
// </div>
// );
// }

return (
<div
{...props}
className={cn("p-4 text-base-8 ", props.className)}
style={{ minWidth: "min(500px, 100vw)" }}
ref={ref}
>
Loading...
</div>
);
}
Loading

0 comments on commit 0e76d2c

Please sign in to comment.