/* * Vencord, a Discord client mod * Copyright (c) 2024 Vendicated and contributors * SPDX-License-Identifier: GPL-3.0-or-later */ import { classNameFactory } from "@api/Styles"; import { closeModal, ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot, openModal } from "@utils/modal"; import { LazyComponent } from "@utils/react"; import { Button, React, RelationshipStore, Select, Text, TextInput, useCallback, useMemo, useReducer, useState } from "@webpack/common"; import { cacheUsers, getNotes, usersCache as usersCache$1 } from "../data"; import NotesDataRow from "./NotesDataRow"; const cl = classNameFactory("vc-notes-searcher-modal-"); const enum SearchStatus { ALL, FRIENDS, BLOCKED, } const filterUser = (query: string, userId: string, userNotes: string) => { if (query === "" || userId.includes(query)) return true; query = query.toLowerCase(); const user = usersCache$1.get(userId); return user && ( user.globalName?.toLowerCase().includes(query) || user.username.toLowerCase().includes(query) ) || userNotes.toLowerCase().includes(query); }; // looks like a shit but I don't know better way to do it // P.S. using `getNotes()` as deps for useMemo won't work due to object init outside of component let RefreshNotesDataEx: () => void | undefined; export const refreshNotesData = () => { if (!RefreshNotesDataEx) return; RefreshNotesDataEx(); }; export function NotesDataModal({ modalProps, close }: { modalProps: ModalProps; close(): void; }) { const [searchValue, setSearchValue] = useState({ query: "", status: SearchStatus.ALL }); const onSearch = (query: string) => setSearchValue(prev => ({ ...prev, query })); const onStatusChange = (status: SearchStatus) => setSearchValue(prev => ({ ...prev, status })); const [usersNotesData, refreshNotesData] = useReducer(() => { return Object.entries(getNotes()) .map<[string, string]>(([userId, { note }]) => [userId, note]) .filter((([_, note]) => note && note !== "")); }, Object.entries(getNotes()) .map<[string, string]>(([userId, { note }]) => [userId, note]) .filter((([_, note]) => note && note !== "")) ); RefreshNotesDataEx = refreshNotesData; const filteredNotes = useMemo(() => { const { query, status } = searchValue; if (query === "" && status === SearchStatus.ALL) { return usersNotesData; } return usersNotesData .filter(([userId, userNotes]) => { switch (status) { case SearchStatus.FRIENDS: return RelationshipStore.isFriend(userId) && filterUser(query, userId, userNotes); case SearchStatus.BLOCKED: return RelationshipStore.isBlocked(userId) && filterUser(query, userId, userNotes); default: return filterUser(query, userId, userNotes); } }); }, [usersNotesData, searchValue]); const [visibleNotesNum, setVisibleNotesNum] = useState(10); const loadMore = useCallback(() => { setVisibleNotesNum(prevNum => prevNum + 10); }, []); const visibleNotes = filteredNotes.slice(0, visibleNotesNum); const canLoadMore = visibleNotesNum < filteredNotes.length; return ( User Notes