Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reorganize global hooks + components #131

Merged
merged 2 commits into from
Oct 7, 2023
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
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React, { type MouseEventHandler } from "react";
import { type MouseEventHandler } from "react";

import {
getAmbassadorImages,
type AmbassadorKey,
type Ambassador as AmbassadorType,
} from "../../ambassadors";
import { classes } from "../../classes";
} from "../../utils/ambassadors";
import { classes } from "../../utils/classes";

import styles from "./ambassadorButton.module.scss";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import "../../../variables.scss";
@import "../../variables.scss";

.ambassador {
display: flex;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import { calculateAge, formatDate, isBirthday } from "../../dateManager";
import { calculateAge, formatDate, isBirthday } from "../../utils/dateManager";
import {
getClassification,
getAmbassadorImages,
getIUCNStatus,
type AmbassadorKey,
type Ambassador as AmbassadorType,
} from "../../ambassadors";
import { normalizeAmbassadorName } from "../../chatCommand";
import { camelToKebab } from "../../helpers";
import { classes } from "../../classes";
} from "../../utils/ambassadors";
import { camelToKebab } from "../../utils/helpers";
import { classes } from "../../utils/classes";

import { normalizeAmbassadorName } from "../../hooks/useChatCommand";

import moderatorBadge from "../../assets/mod.png";

import Tooltip from "../tooltip/Tooltip";

import styles from "./ambassadorCard.module.scss";
import moderatorBadge from "../../../assets/mod.png";

export interface AmbassadorCardProps {
ambassadorKey: AmbassadorKey;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import "../../../variables.scss";
@import "../../variables.scss";

.ambassadorCard {
width: 18.5rem;
Expand Down Expand Up @@ -136,7 +136,7 @@
}

.birthday::after {
content: url("../../../assets/partyHat.png");
content: url("../../assets/partyHat.png");
width: 4rem;
height: auto;
position: absolute;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import React, {
import {
useCallback,
useRef,
useState,
type MouseEvent,
useMemo,
useId,
type FocusEvent,
Children,
isValidElement,
cloneElement,
} from "react";

import styles from "./tooltip.module.scss";
Expand All @@ -17,7 +20,7 @@ interface TooltipProps {
maxWidth?: string;
}

const Tooltip: React.FC<TooltipProps> = (props) => {
const Tooltip = (props: TooltipProps) => {
const { text, children, fontSize, maxWidth } = props;

const id = useId();
Expand Down Expand Up @@ -58,10 +61,10 @@ const Tooltip: React.FC<TooltipProps> = (props) => {
// Add event listeners + refs to the children to show/hide tooltip
const childrenWithProps = useMemo(
() =>
React.Children.map(children, (child) => {
if (!React.isValidElement(child)) return child;
Children.map(children, (child) => {
if (!isValidElement(child)) return child;

return React.cloneElement(child as React.ReactElement, {
return cloneElement(child as React.ReactElement, {
onMouseEnter: handleEnter,
onFocus: handleEnter,
onMouseLeave: () => setShow(false),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import "../../../variables.scss";
@import "../../variables.scss";

.tooltip {
background-color: $tooltip-background-color;
Expand Down
8 changes: 5 additions & 3 deletions src/utils/chatCommand.ts → src/hooks/useChatCommand.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { useCallback, useEffect, useMemo, useState } from "react";
import tmi, { ChatUserstate } from "tmi.js";

import { ambassadors, AmbassadorKey } from "./ambassadors";
import { typeSafeObjectEntries } from "./helpers";
import { fetchCurrentChannelInfo, useTwitchAuth } from "./twitch-api";
import { ambassadors, AmbassadorKey } from "../utils/ambassadors";
import { typeSafeObjectEntries } from "../utils/helpers";
import { fetchCurrentChannelInfo } from "../utils/twitchApi";

import useTwitchAuth from "./useTwitchAuth";

const testChannelNames =
process.env.REACT_APP_TEST_CHANNEL_NAMES?.split(",") ?? [];
Expand Down
41 changes: 4 additions & 37 deletions src/utils/twitch-api.ts → src/hooks/useTwitchAuth.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,5 @@
import { useSyncExternalStore } from "react";

type ChannelsResponse = {
data: Array<ChannelInfo>;
};

type ChannelInfo = {
broadcaster_id: string;
broadcaster_login: string;
broadcaster_name: string;
broadcaster_language: string;
game_id: string;
game_name: string;
title: string;
delay: number;
tags: string[];
};

export async function fetchCurrentChannelInfo(auth: Twitch.ext.Authorized) {
const url = new URL("https://api.twitch.tv/helix/channels");
url.searchParams.set("broadcaster_id", auth.channelId);

const response = await fetch(url, {
headers: {
"client-id": auth.clientId,
Authorization: `Extension ${auth.helixToken}`,
},
});

const data = (await response.json()) as ChannelsResponse; // TODO: validate schema?
if (data?.data?.length) return data.data[0];

return null;
}

const authStore = {
value: null as Twitch.ext.Authorized | null,
listeners: [] as (() => void)[],
Expand All @@ -49,10 +16,6 @@ const authStore = {
},
};

// Twitch auth callback may be called before React is ready, so we use an external store
export const useTwitchAuth = () =>
useSyncExternalStore(authStore.subscribe, authStore.snapshot);

export const bindTwitchAuth = () => {
// If Twitch isn't available, do nothing
if (!("Twitch" in window) || !window.Twitch.ext) return;
Expand All @@ -62,3 +25,7 @@ export const bindTwitchAuth = () => {
authStore.update(auth);
});
};

// Twitch auth callback may be called before React is ready, so we use an external store
export default () =>
useSyncExternalStore(authStore.subscribe, authStore.snapshot);
4 changes: 3 additions & 1 deletion src/pages/overlay/App.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import React, { useEffect, useCallback } from "react";
import { useEffect, useCallback } from "react";

import { classes } from "../../utils/classes";

import useHiddenCursor from "./hooks/useHiddenCursor";
import useSettings from "./hooks/useSettings";
import useSleeping from "./hooks/useSleeping";

import Overlay from "./components/overlay/Overlay";

import styles from "./App.module.scss";

// Hide the overlay after 5s of inactivity
Expand Down
3 changes: 2 additions & 1 deletion src/pages/overlay/components/buttons/Buttons.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useMemo } from "react";

import Tooltip from "../../../../components/tooltip/Tooltip";

import { classes } from "../../../../utils/classes";
import Tooltip from "../../../../utils/global/tooltip/Tooltip";

import styles from "./buttons.module.scss";

Expand Down
10 changes: 6 additions & 4 deletions src/pages/overlay/components/overlay/Overlay.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {
import {
useEffect,
useRef,
useCallback,
Expand All @@ -8,14 +8,14 @@ import React, {
type Dispatch,
} from "react";

import Buttons from "../buttons/Buttons";

import useChatCommand from "../../../../utils/chatCommand";
import {
isAmbassadorKey,
type AmbassadorKey,
} from "../../../../utils/ambassadors";
import { classes } from "../../../../utils/classes";

import useChatCommand from "../../../../hooks/useChatCommand";

import useSettings from "../../hooks/useSettings";
import useSleeping from "../../hooks/useSleeping";

Expand All @@ -28,6 +28,8 @@ import AmbassadorsOverlay from "./ambassadors/Ambassadors";
import SettingsIcon from "../../../../assets/overlay/settings.png";
import SettingsOverlay from "./settings/Settings";

import Buttons from "../buttons/Buttons";

import styles from "./overlay.module.scss";

// Show command-triggered popups for 10s
Expand Down
10 changes: 6 additions & 4 deletions src/pages/overlay/components/overlay/ambassadors/Ambassadors.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import React, { useRef, useEffect, useCallback } from "react";
import { useRef, useEffect, useCallback } from "react";

import AmbassadorCard from "../../../../../components/ambassadorCard/AmbassadorCard";
import AmbassadorButton from "../../../../../components/ambassadorButton/AmbassadorButton";

import AmbassadorCard from "../../../../../utils/global/ambassadorCard/AmbassadorCard";
import AmbassadorButton from "../../../../../utils/global/ambassadorButton/AmbassadorButton";
import {
sortedAmbassadors,
ambassadors,
} from "../../../../../utils/ambassadors";
import { classes } from "../../../../../utils/classes";
import type { OverlayOptionProps } from "../Overlay";

import arrow from "../../../../../assets/arrow.png";

import type { OverlayOptionProps } from "../Overlay";

import styles from "./ambassadors.module.scss";

export default function Ambassadors(props: OverlayOptionProps) {
Expand Down
2 changes: 2 additions & 0 deletions src/pages/overlay/components/overlay/settings/Settings.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { typeSafeObjectEntries } from "../../../../../utils/helpers";

import useSettings from "../../../hooks/useSettings";

import Card from "../../card/Card";
import Toggle from "../../toggle/Toggle";

import type { OverlayOptionProps } from "../Overlay";

import styles from "./settings.module.scss";
Expand Down
7 changes: 4 additions & 3 deletions src/pages/overlay/components/overlay/welcome/Welcome.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import Card from "../../card/Card";
import type { OverlayOptionProps } from "../Overlay";

import website from "../../../../../assets/welcome/website.png";
import amazonWishlist from "../../../../../assets/welcome/amazonWishlist.png";
import instagram from "../../../../../assets/welcome/instagram.png";
import tiktok from "../../../../../assets/welcome/tiktok.png";
import twitter from "../../../../../assets/welcome/twitter.png";
import gitHub from "../../../../../assets/welcome/github.png";

import Card from "../../card/Card";

import type { OverlayOptionProps } from "../Overlay";

import styles from "./welcome.module.scss";

export default function Welcome(props: OverlayOptionProps) {
Expand Down
2 changes: 1 addition & 1 deletion src/pages/overlay/components/toggle/Toggle.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, type ChangeEvent } from "react";
import { useCallback, type ChangeEvent } from "react";

import styles from "./toggle.module.scss";

Expand Down
2 changes: 1 addition & 1 deletion src/pages/overlay/hooks/useSettings.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {
import {
createContext,
useCallback,
useContext,
Expand Down
2 changes: 1 addition & 1 deletion src/pages/overlay/hooks/useSleeping.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {
import {
createContext,
useCallback,
useContext,
Expand Down
3 changes: 2 additions & 1 deletion src/pages/overlay/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";

import { bindTwitchAuth } from "../../hooks/useTwitchAuth";

import App from "./App";
import { SettingsProvider } from "./hooks/useSettings";
import { SleepingProvider } from "./hooks/useSleeping";
import { bindTwitchAuth } from "../../utils/twitch-api";

import "./index.scss";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { useCallback, type MouseEventHandler } from "react";
import { useCallback, type MouseEventHandler } from "react";

import AmbassadorCard, {
type AmbassadorCardProps,
} from "../../../../utils/global/ambassadorCard/AmbassadorCard";
} from "../../../../components/ambassadorCard/AmbassadorCard";

import styles from "./ambassadorCardOverlay.module.scss";

interface AmbassadorCardOverlayProps {
Expand Down
11 changes: 7 additions & 4 deletions src/pages/panel/components/ambassadorPanel/AmbassadorPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import React, { useState, useCallback, Fragment } from "react";
import { useState, useCallback, Fragment } from "react";

import AmbassadorButton from "../../../../components/ambassadorButton/AmbassadorButton";

import AmbassadorButton from "../../../../utils/global/ambassadorButton/AmbassadorButton";
import AmbassadorCardOverlay from "../ambassadorCardOverlay/AmbassadorCardOverlay";
import useChatCommand from "../../../../utils/chatCommand";
import {
sortedAmbassadors,
isAmbassadorKey,
type AmbassadorKey,
} from "../../../../utils/ambassadors";

import useChatCommand from "../../../../hooks/useChatCommand";

import AmbassadorCardOverlay from "../ambassadorCardOverlay/AmbassadorCardOverlay";

import styles from "./ambassadorPanel.module.scss";

export default function AmbassadorPanel() {
Expand Down
1 change: 1 addition & 0 deletions src/pages/panel/components/nav/Nav.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import AlveusLogo from "../../../../assets/alveus-logo.png";

import styles from "./nav.module.scss";

export default function Nav() {
Expand Down
3 changes: 2 additions & 1 deletion src/pages/panel/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";

import { bindTwitchAuth } from "../../hooks/useTwitchAuth";

import App from "./App";
import { bindTwitchAuth } from "../../utils/twitch-api";

import "./index.scss";

Expand Down
Loading