diff --git a/manifest.json b/manifest.json index 5776267..6f4dec6 100644 --- a/manifest.json +++ b/manifest.json @@ -2,11 +2,18 @@ "id": "dev.wolfplugs.decor", "name": "Decor plugin", "description": "Adds Custom Decoration to your profile", - "author": { - "name": "Wolfkid200444", - "discordID": "347096063569559553", - "github": "WolfPlugs" - }, + "author": [ + { + "name": "Wolfkid200444", + "discordID": "347096063569559553", + "github": "WolfPlugs" + }, + { + "name": "Ahlawat", + "discordID": "1025214794766221384", + "github": "TharkiDev" + } + ], "version": "1.0.0", "updater": { "type": "github", diff --git a/src/lib/api.ts b/src/lib/api.ts index 539092c..490910f 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -1,6 +1,5 @@ import { API_URL } from "./constants"; -import { useAuthorizationStore } from "./stores/AuthorizationStore"; - +import { authorizationStore } from "./stores/AuthorizationStore"; export interface Preset { id: string; @@ -31,7 +30,7 @@ export async function fetchApi(url: RequestInfo, options?: RequestInit) { ...options, headers: { ...options?.headers, - Authorization: `Bearer ${useAuthorizationStore.getState().token}`, + Authorization: `Bearer ${authorizationStore.token}`, }, }); @@ -53,4 +52,5 @@ export const getUserDecorations = async (id: string = "@me"): Promise => fetchApi(API_URL + `/users/${id}/decoration`).then((c) => c.json()); -export const getPresets = async (): Promise => fetch(API_URL + "/decorations/presets").then(c => c.json()); +export const getPresets = async (): Promise => + fetch(API_URL + "/decorations/presets").then((c) => c.json()); diff --git a/src/lib/stores/AuthorizationStore.ts b/src/lib/stores/AuthorizationStore.ts index 141520e..88eb49b 100644 --- a/src/lib/stores/AuthorizationStore.ts +++ b/src/lib/stores/AuthorizationStore.ts @@ -16,44 +16,31 @@ interface AuthorizationState { isAuthorized: () => boolean; } -const indexedDBStorage: StateStorage = { - async getItem(name: string): Promise { - return (await authorizationToken).get(name).then((v) => v ?? null); +export const authorizationStore = { + get token() { + return authorizationToken.get("token", null); }, - async setItem(name: string, value: string): Promise { - (await authorizationToken).set(name, value); + get tokens() { + return authorizationToken.get("tokens", { + [users.getCurrentUser().id]: authorizationToken.get("token", null), + }); }, - async removeItem(name: string): Promise { - (await authorizationToken).set(name, null); + init: () => {}, + setToken: (token: string) => { + authorizationToken.set("token", token); + authorizationToken.set("tokens", { + ...authorizationToken.get("tokens", {}), + [users.getCurrentUser().id]: token, + }); }, -}; - -export const useAuthorizationStore = create( - persist( - (set, get) => ({ - token: null, - tokens: {}, - init: () => { - set({ token: get().tokens[users.getCurrentUser().id] ?? null }); - }, - setToken: (token: string) => - set({ token, tokens: { ...get().tokens, [users.getCurrentUser().id]: token } }), - remove: (id: string) => { - const { tokens, init } = get(); - const newTokens = { ...tokens }; - delete newTokens[id]; - set({ tokens: newTokens }); + remove: (id: string) => { + const tokens = authorizationToken.get("tokens", {}); - init(); - }, - authorize: () => void showAuthorizationModal(), - isAuthorized: () => !!get().token, - }), - { - name: "decor-auth", - getStorage: () => indexedDBStorage, - partialize: (state) => ({ tokens: state.tokens }), - onRehydrateStorage: () => (state) => state?.init(), - }, - ), -); + delete tokens[id]; + authorizationToken.set("tokens", tokens); + }, + authorize: () => void showAuthorizationModal(), + get isAuthorized() { + return () => Boolean(authorizationToken.get("token", null)); + }, +}; diff --git a/src/lib/stores/UserDecorationsStore.ts b/src/lib/stores/UserDecorationsStore.ts index 5af7e2b..7b481fe 100644 --- a/src/lib/stores/UserDecorationsStore.ts +++ b/src/lib/stores/UserDecorationsStore.ts @@ -5,7 +5,7 @@ import { DECORATION_FETCH_COOLDOWN, SKU_ID } from "../constants"; import { AvatarDecoration } from "../.."; import subscribeToFluxDispatcher from "../utils/subscribeToFluxDispatcher"; import { useCurrentUserDecorationsStore } from "./CurrentUserDecorationsStore"; -import { useAuthorizationStore } from "./AuthorizationStore"; +import { authorizationStore } from "./AuthorizationStore"; const { lodash, users, fluxDispatcher, React, channels } = common; @@ -31,7 +31,7 @@ export const useUsersDecorationsStore = create((set, get) fetchQueue: new Set(), bulkFetch: lodash.debounce(async () => { const { fetchQueue, usersDecorations } = get(); - set({ fetchQueue: new Set() }); + set({ fetchQueue: new Set() }); const fetchIds = Array.from(fetchQueue); if (fetchIds.length === 0) return; @@ -112,7 +112,6 @@ export const subscriptions = [ }), subscribeToFluxDispatcher("CONNECTION_OPEN", () => { - useAuthorizationStore.getState().init(); useCurrentUserDecorationsStore.getState().clear(); useUsersDecorationsStore.getState().fetch(users.getCurrentUser().id, true); }), @@ -145,7 +144,7 @@ export function useUserDecorAvatarDecoration(user): AvatarDecoration | null | un fetchUserDecorAvatarDecoration(user.id); }, []); - console.log("Effects", decorAvatarDecoration) + console.log("Effects", decorAvatarDecoration); return decorAvatarDecoration ? { asset: decorAvatarDecoration, skuId: SKU_ID } : null; } diff --git a/src/lib/utils/settings.ts b/src/lib/utils/settings.ts index c9baf92..79a865d 100644 --- a/src/lib/utils/settings.ts +++ b/src/lib/utils/settings.ts @@ -1,4 +1,4 @@ -import { settings } from "replugged" +import { settings } from "replugged"; -export const defaultSettings = {} -export const authorizationToken = settings.init("decor.auth", defaultSettings) +export const defaultSettings = {}; +export const authorizationToken = await settings.init("decor.auth", defaultSettings); diff --git a/src/lib/utils/showAuthorizationModal.tsx b/src/lib/utils/showAuthorizationModal.tsx index 1c8f1c3..ef52a80 100644 --- a/src/lib/utils/showAuthorizationModal.tsx +++ b/src/lib/utils/showAuthorizationModal.tsx @@ -1,13 +1,17 @@ -import { webpack, common } from "replugged" -import { useAuthorizationStore } from "../stores/AuthorizationStore"; +import { webpack, common } from "replugged"; +import { authorizationStore } from "../stores/AuthorizationStore"; import { AUTHORIZE_URL, CLIENT_ID } from "../constants"; import { logger } from "../.."; -const { modal: { openModal } } = common -const OAuth = webpack.getByProps("OAuth2AuthorizeModal") +const { + modal: { openModal }, +} = common; +const OAuth = webpack.getByProps("OAuth2AuthorizeModal"); -export default async () => new Promise(r => openModal(props => - + new Promise((r) => + openModal((props) => ( + new Promise(r => openModal(props => clientId={CLIENT_ID} cancelCompletesFlow={false} callback={async (response: any) => { - try { - const url = new URL(response.location); - url.searchParams.append("client", "replugged"); + try { + const url = new URL(response.location); + url.searchParams.append("client", "replugged"); - const req = await fetch(url); + const req = await fetch(url); - if (req?.ok) { - const token = await req.text(); - useAuthorizationStore.getState().setToken(token); - } else { - throw new Error("Request not OK"); - } - r(void 0); - } catch (e) { - logger.error("Decor: Failed to authorize", e); + if (req?.ok) { + const token = await req.text(); + authorizationStore.setToken(token); + } else { + throw new Error("Request not OK"); } + r(void 0); + } catch (e) { + logger.error("Decor: Failed to authorize", e); + } }} - /> -)) - - + /> + )), + ); diff --git a/src/ui/components/DecorSection.tsx b/src/ui/components/DecorSection.tsx index 9c78161..28ebbb1 100644 --- a/src/ui/components/DecorSection.tsx +++ b/src/ui/components/DecorSection.tsx @@ -1,56 +1,63 @@ import { webpack, common, components } from "replugged"; -import { useAuthorizationStore } from "../../lib/stores/AuthorizationStore"; +import { authorizationStore } from "../../lib/stores/AuthorizationStore"; import { useCurrentUserDecorationsStore } from "../../lib/stores/CurrentUserDecorationsStore"; import { cl } from ".."; import { openChangeDecorationModal } from "../modals/ChangeDecorationModal"; -const { React } = common -const { Flex, Button } = components +const { React } = common; +const { Flex, Button } = components; let CustomizationSection; - interface DecorSectionProps { hideTitle?: boolean; hideDivider?: boolean; noMargin?: boolean; } - -export default function DecorSection({ hideTitle = false, hideDivider = false, noMargin = false }: DecorSectionProps) { +export default function DecorSection({ + hideTitle = false, + hideDivider = false, + noMargin = false, +}: DecorSectionProps) { CustomizationSection ??= webpack.getBySource(".customizationSectionBackground"); - const authorization = useAuthorizationStore(); - const { selectedDecoration, select: selectDecoration, fetch: fetchDecorations } = useCurrentUserDecorationsStore(); - + const { + selectedDecoration, + select: selectDecoration, + fetch: fetchDecorations, + } = useCurrentUserDecorationsStore(); + React.useEffect(() => { - if (authorization.isAuthorized()) fetchDecorations(); - }, [authorization.token]); + if (authorizationStore.isAuthorized()) fetchDecorations(); + }, [authorizationStore.token]); - return - - - {selectedDecoration && authorization.isAuthorized() && } - - + return ( + + + + {selectedDecoration && authorizationStore.isAuthorized() && ( + + )} + + + ); } diff --git a/src/ui/modals/ChangeDecorationModal.tsx b/src/ui/modals/ChangeDecorationModal.tsx index 511bb66..45d0c2b 100644 --- a/src/ui/modals/ChangeDecorationModal.tsx +++ b/src/ui/modals/ChangeDecorationModal.tsx @@ -8,26 +8,42 @@ import DecorationGridNone from "../components/DecorationGridNone"; import DecorationGridCreate from "../components/DecorationGridCreate"; import { NavigationRouter, openCreateDecorationModal } from "../modals/CreateDecorationModal"; import DecorDecorationGridDecoration from "../components/DecorDecorationGridDecoration"; -import { useAuthorizationStore } from "../../lib/stores/AuthorizationStore"; +import { authorizationStore } from "../../lib/stores/AuthorizationStore"; import { openInviteModal } from "./openInviteModal"; import { Margins } from "../../Settings"; import { AvatarDecorationModalPreview } from "../components"; import { GUILD_ID, INVITE_KEY } from "../../lib/constants"; -const { React, users, parser, guilds, fluxDispatcher, modal: { openModal } } = common -const { FormText, Flex, Modal: { ModalRoot, ModalHeader, ModalCloseButton, ModalContent, ModalFooter }, Text, Tooltip, Button, ErrorBoundary } = components +const { + React, + users, + parser, + guilds, + fluxDispatcher, + modal: { openModal }, +} = common; +const { + FormText, + Flex, + Modal: { ModalRoot, ModalHeader, ModalCloseButton, ModalContent, ModalFooter }, + Text, + Tooltip, + Button, + ErrorBoundary, +} = components; -const UserSummaryItem = webpack.getBySource(["defaultRenderUser", "showDefaultAvatarsForNullUsers"]) -const DecorationModalStyles = webpack.getByProps("modalFooterShopButton") +const UserSummaryItem = webpack.getBySource("UserSummaryItem"); +const DecorationModalStyles = webpack.getByProps("modalFooterShopButton"); const modals = webpack.getByProps("openModalLazy"); function usePresets() { - const [presets, setPresets] = React.useState([]) - React.useEffect(() => { getPresets().then(setPresets) }, []) - return presets + const [presets, setPresets] = React.useState([]); + React.useEffect(() => { + getPresets().then(setPresets); + }, []); + return presets; } - interface Section { title: string; subtitle?: string; @@ -36,59 +52,64 @@ interface Section { authorIds?: string[]; } -function SectionHeader({ section }: { section: Section; }) { +function SectionHeader({ section }: { section: Section }) { const hasSubtitle = typeof section.subtitle !== "undefined"; const hasAuthorIds = typeof section.authorIds !== "undefined"; const [authors, setAuthors] = React.useState([]); - React.useEffect(() => { (async () => { if (!section.authorIds) return; for (const authorId of section.authorIds) { - const author = users.getUser(authorId) ?? await users.getUser(authorId); - setAuthors(authors => [...authors, author]); + const author = users.getUser(authorId) ?? (await users.getUser(authorId)); + setAuthors((authors) => [...authors, author]); } })(); }, [section.authorIds]); - return
- - {section.title} - {hasAuthorIds && - } - - {hasSubtitle && - - {section.subtitle} - - } -
; + return ( +
+ + {section.title} + {hasAuthorIds && ( + + )} + + {hasSubtitle && ( + + {section.subtitle} + + )} +
+ ); } export default function ChangeDecorationModal(props: any) { // undefined = not trying, null = none, Decoration = selected - const [tryingDecoration, setTryingDecoration] = React.useState(undefined); + const [tryingDecoration, setTryingDecoration] = React.useState( + undefined, + ); const isTryingDecoration = typeof tryingDecoration !== "undefined"; - const avatarDecorationOverride = tryingDecoration != null ? decorationToAvatarDecoration(tryingDecoration) : tryingDecoration; + const avatarDecorationOverride = + tryingDecoration != null ? decorationToAvatarDecoration(tryingDecoration) : tryingDecoration; const { decorations, selectedDecoration, fetch: fetchUserDecorations, - select: selectDecoration + select: selectDecoration, } = useCurrentUserDecorationsStore(); React.useEffect(() => { @@ -97,53 +118,50 @@ export default function ChangeDecorationModal(props: any) { const activeSelectedDecoration = isTryingDecoration ? tryingDecoration : selectedDecoration; const activeDecorationHasAuthor = typeof activeSelectedDecoration?.authorId !== "undefined"; - const hasDecorationPendingReview = decorations.some(d => d.reviewed === false); + const hasDecorationPendingReview = decorations.some((d) => d.reviewed === false); const presets = usePresets(); - const presetDecorations = presets.flatMap(preset => preset.decorations); + const presetDecorations = presets.flatMap((preset) => preset.decorations); - const activeDecorationPreset = presets.find(preset => preset.id === activeSelectedDecoration?.presetId); + const activeDecorationPreset = presets.find( + (preset) => preset.id === activeSelectedDecoration?.presetId, + ); const isActiveDecorationPreset = typeof activeDecorationPreset !== "undefined"; - const ownDecorations = decorations.filter(d => !presetDecorations.some(p => p.hash === d.hash)); + const ownDecorations = decorations.filter( + (d) => !presetDecorations.some((p) => p.hash === d.hash), + ); const data = [ { title: "Your Decorations", sectionKey: "ownDecorations", - items: ["none", ...ownDecorations, "create"] + items: ["none", ...ownDecorations, "create"], }, - ...presets.map(preset => ({ + ...presets.map((preset) => ({ title: preset.name, subtitle: preset.description || undefined, sectionKey: `preset-${preset.id}`, items: preset.decorations, - authorIds: preset.authorIds - })) + authorIds: preset.authorIds, + })), ] as Section[]; - return - - - - Change Decoration - - - - - {/* + + + + Change Decoration + + + + + {/* { if (typeof item === "string") { switch (item) { @@ -181,7 +199,7 @@ export default function ChangeDecorationModal(props: any) { renderSectionHeader={section => } sections={data} /> */} - {/*
+ {/*
Created by {parser.parse(`<@${activeSelectedDecoration.authorId}>`)}}
*/} - - -
- - -
-
- - - {tooltipProps => + +
+
+ } - -
-
- - ; + look={Button.Looks.LINK}> + Log Out + + + {(tooltipProps) => ( + + )} + +
+ +
+
+ ); } export const openChangeDecorationModal = () => - openModal(props => ); + openModal((props) => );