aboutsummaryrefslogtreecommitdiff
path: root/src/api/Badges.ts
blob: d4aabaf21ced8de22c2e6f407d16834091b95d74 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/*
 * Vencord, a modification for Discord's desktop app
 * Copyright (c) 2022 Vendicated and contributors
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

import ErrorBoundary from "@components/ErrorBoundary";
import { User } from "discord-types/general";
import { ComponentType, HTMLProps } from "react";

import Plugins from "~plugins";

export enum BadgePosition {
    START,
    END
}

export interface ProfileBadge {
    /** The tooltip to show on hover. Required for image badges */
    tooltip?: string;
    /** Custom component for the badge (tooltip not included) */
    component?: ComponentType<ProfileBadge & BadgeUserArgs>;
    /** The custom image to use */
    image?: string;
    /** Action to perform when you click the badge */
    onClick?(): void;
    /** Should the user display this badge? */
    shouldShow?(userInfo: BadgeUserArgs): boolean;
    /** Optional props (e.g. style) for the badge, ignored for component badges */
    props?: HTMLProps<HTMLImageElement>;
    /** Insert at start or end? */
    position?: BadgePosition;
    /** The badge name to display, Discord uses this. Required for component badges */
    key?: string;
}

const Badges = new Set<ProfileBadge>();

/**
 * Register a new badge with the Badges API
 * @param badge The badge to register
 */
export function addBadge(badge: ProfileBadge) {
    badge.component &&= ErrorBoundary.wrap(badge.component, { noop: true });
    Badges.add(badge);
}

/**
 * Unregister a badge from the Badges API
 * @param badge The badge to remove
 */
export function removeBadge(badge: ProfileBadge) {
    return Badges.delete(badge);
}

/**
 * Inject badges into the profile badges array.
 * You probably don't need to use this.
 */
export function inject(badgeArray: ProfileBadge[], args: BadgeUserArgs) {
    for (const badge of Badges) {
        if (!badge.shouldShow || badge.shouldShow(args)) {
            badge.position === BadgePosition.START
                ? badgeArray.unshift({ ...badge, ...args })
                : badgeArray.push({ ...badge, ...args });
        }
    }
    (Plugins.BadgeAPI as any).addDonorBadge(badgeArray, args.user.id);

    return badgeArray;
}

export interface BadgeUserArgs {
    user: User;
    profile: Profile;
    premiumSince: Date;
    premiumGuildSince?: Date;
}

interface ConnectedAccount {
    type: string;
    id: string;
    name: string;
    verified: boolean;
}

interface Profile {
    connectedAccounts: ConnectedAccount[];
    premiumType: number;
    premiumSince: string;
    premiumGuildSince?: any;
    lastFetched: number;
    profileFetchFailed: boolean;
    application?: any;
}