import { None, Option, Some } from "@sniptt/monads"; import { Component, linkEvent } from "inferno"; import { BlockCommunity, BlockCommunityResponse, BlockPerson, BlockPersonResponse, ChangePassword, CommunityBlockView, CommunityView, DeleteAccount, GetSiteResponse, ListingType, LoginResponse, PersonBlockView, PersonViewSafe, SaveUserSettings, SortType, toUndefined, UserOperation, wsJsonToRes, wsUserOp, } from "lemmy-js-client"; import { Subscription } from "rxjs"; import { i18n, languages } from "../../i18next"; import { UserService, WebSocketService } from "../../services"; import { auth, capitalizeFirstLetter, choicesConfig, communitySelectName, communityToChoice, debounce, elementUrl, enableNsfw, fetchCommunities, fetchThemeList, fetchUsers, getLanguages, isBrowser, personSelectName, personToChoice, relTags, setIsoData, setTheme, setupTippy, showLocal, toast, updateCommunityBlock, updatePersonBlock, wsClient, wsSubscribe, } from "../../utils"; import { HtmlTags } from "../common/html-tags"; import { Icon, Spinner } from "../common/icon"; import { ImageUploadForm } from "../common/image-upload-form"; import { LanguageSelect } from "../common/language-select"; import { ListingTypeSelect } from "../common/listing-type-select"; import { MarkdownTextArea } from "../common/markdown-textarea"; import { SortSelect } from "../common/sort-select"; import { CommunityLink } from "../community/community-link"; import { PersonListing } from "./person-listing"; var Choices: any; if (isBrowser()) { Choices = require("choices.js"); } interface SettingsState { saveUserSettingsForm: SaveUserSettings; changePasswordForm: ChangePassword; deleteAccountForm: DeleteAccount; personBlocks: PersonBlockView[]; blockPerson: Option; communityBlocks: CommunityBlockView[]; blockCommunityId: number; blockCommunity?: CommunityView; currentTab: string; themeList: string[]; saveUserSettingsLoading: boolean; changePasswordLoading: boolean; deleteAccountLoading: boolean; deleteAccountShowConfirm: boolean; siteRes: GetSiteResponse; } export class Settings extends Component { private isoData = setIsoData(this.context); private blockPersonChoices: any; private blockCommunityChoices: any; private subscription: Subscription; private emptyState: SettingsState = { saveUserSettingsForm: new SaveUserSettings({ show_nsfw: None, show_scores: None, show_avatars: None, show_read_posts: None, show_bot_accounts: None, show_new_post_notifs: None, default_sort_type: None, default_listing_type: None, theme: None, interface_language: None, discussion_languages: None, avatar: None, banner: None, display_name: None, email: None, bio: None, matrix_user_id: None, send_notifications_to_email: None, bot_account: None, auth: undefined, }), changePasswordForm: new ChangePassword({ new_password: undefined, new_password_verify: undefined, old_password: undefined, auth: undefined, }), saveUserSettingsLoading: false, changePasswordLoading: false, deleteAccountLoading: false, deleteAccountShowConfirm: false, deleteAccountForm: new DeleteAccount({ password: undefined, auth: undefined, }), personBlocks: [], blockPerson: None, communityBlocks: [], blockCommunityId: 0, currentTab: "settings", siteRes: this.isoData.site_res, themeList: [], }; constructor(props: any, context: any) { super(props, context); this.state = this.emptyState; this.handleSortTypeChange = this.handleSortTypeChange.bind(this); this.handleListingTypeChange = this.handleListingTypeChange.bind(this); this.handleBioChange = this.handleBioChange.bind(this); this.handleDiscussionLanguageChange = this.handleDiscussionLanguageChange.bind(this); this.handleAvatarUpload = this.handleAvatarUpload.bind(this); this.handleAvatarRemove = this.handleAvatarRemove.bind(this); this.handleBannerUpload = this.handleBannerUpload.bind(this); this.handleBannerRemove = this.handleBannerRemove.bind(this); this.parseMessage = this.parseMessage.bind(this); this.subscription = wsSubscribe(this.parseMessage); if (UserService.Instance.myUserInfo.isSome()) { let mui = UserService.Instance.myUserInfo.unwrap(); let luv = mui.local_user_view; this.state = { ...this.state, personBlocks: mui.person_blocks, communityBlocks: mui.community_blocks, saveUserSettingsForm: { ...this.state.saveUserSettingsForm, show_nsfw: Some(luv.local_user.show_nsfw), theme: Some(luv.local_user.theme ? luv.local_user.theme : "browser"), default_sort_type: Some(luv.local_user.default_sort_type), default_listing_type: Some(luv.local_user.default_listing_type), interface_language: Some(luv.local_user.interface_language), discussion_languages: Some(mui.discussion_languages.map(l => l.id)), avatar: luv.person.avatar, banner: luv.person.banner, display_name: luv.person.display_name, show_avatars: Some(luv.local_user.show_avatars), bot_account: Some(luv.person.bot_account), show_bot_accounts: Some(luv.local_user.show_bot_accounts), show_scores: Some(luv.local_user.show_scores), show_read_posts: Some(luv.local_user.show_read_posts), show_new_post_notifs: Some(luv.local_user.show_new_post_notifs), email: luv.local_user.email, bio: luv.person.bio, send_notifications_to_email: Some( luv.local_user.send_notifications_to_email ), matrix_user_id: luv.person.matrix_user_id, }, }; } } async componentDidMount() { setupTippy(); this.setState({ themeList: await fetchThemeList() }); } componentWillUnmount() { this.subscription.unsubscribe(); } get documentTitle(): string { return i18n.t("settings"); } render() { return (
<>
{this.state.currentTab == "settings" && this.userSettings()} {this.state.currentTab == "blocks" && this.blockCards()}
); } userSettings() { return (
{this.saveUserSettingsHtmlForm()}
{this.changePasswordHtmlForm()}
); } blockCards() { return (
{this.blockUserCard()}
{this.blockCommunityCard()}
); } changePasswordHtmlForm() { return ( <>
{i18n.t("change_password")}
); } blockUserCard() { return (
{this.blockUserForm()} {this.blockedUsersList()}
); } blockedUsersList() { return ( <>
{i18n.t("blocked_users")}
); } blockUserForm() { return (
); } blockCommunityCard() { return (
{this.blockCommunityForm()} {this.blockedCommunitiesList()}
); } blockedCommunitiesList() { return ( <>
{i18n.t("blocked_communities")}
); } blockCommunityForm() { return (
); } saveUserSettingsHtmlForm() { let selectedLangs = this.state.saveUserSettingsForm.discussion_languages; return ( <>
{i18n.t("settings")}
{enableNsfw(this.state.siteRes) && (
)}

{this.state.deleteAccountShowConfirm && ( <>
{i18n.t("delete_account_confirm")}
)}
); } setupBlockPersonChoices() { if (isBrowser()) { let selectId: any = document.getElementById("block-person-filter"); if (selectId) { this.blockPersonChoices = new Choices(selectId, choicesConfig); this.blockPersonChoices.passedElement.element.addEventListener( "choice", (e: any) => { this.handleBlockPerson(Number(e.detail.choice.value)); }, false ); this.blockPersonChoices.passedElement.element.addEventListener( "search", debounce(async (e: any) => { try { let persons = (await fetchUsers(e.detail.value)).users; let choices = persons.map(pvs => personToChoice(pvs)); this.blockPersonChoices.setChoices( choices, "value", "label", true ); } catch (err) { console.error(err); } }), false ); } } } setupBlockCommunityChoices() { if (isBrowser()) { let selectId: any = document.getElementById("block-community-filter"); if (selectId) { this.blockCommunityChoices = new Choices(selectId, choicesConfig); this.blockCommunityChoices.passedElement.element.addEventListener( "choice", (e: any) => { this.handleBlockCommunity(Number(e.detail.choice.value)); }, false ); this.blockCommunityChoices.passedElement.element.addEventListener( "search", debounce(async (e: any) => { try { let communities = (await fetchCommunities(e.detail.value)) .communities; let choices = communities.map(cv => communityToChoice(cv)); this.blockCommunityChoices.setChoices( choices, "value", "label", true ); } catch (err) { console.log(err); } }), false ); } } } handleBlockPerson(personId: number) { if (personId != 0) { let blockUserForm = new BlockPerson({ person_id: personId, block: true, auth: auth().unwrap(), }); WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm)); } } handleUnblockPerson(i: { ctx: Settings; recipientId: number }) { let blockUserForm = new BlockPerson({ person_id: i.recipientId, block: false, auth: auth().unwrap(), }); WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm)); } handleBlockCommunity(community_id: number) { if (community_id != 0) { let blockCommunityForm = new BlockCommunity({ community_id, block: true, auth: auth().unwrap(), }); WebSocketService.Instance.send( wsClient.blockCommunity(blockCommunityForm) ); } } handleUnblockCommunity(i: { ctx: Settings; communityId: number }) { let blockCommunityForm = new BlockCommunity({ community_id: i.communityId, block: false, auth: auth().unwrap(), }); WebSocketService.Instance.send(wsClient.blockCommunity(blockCommunityForm)); } handleShowNsfwChange(i: Settings, event: any) { i.state.saveUserSettingsForm.show_nsfw = Some(event.target.checked); i.setState(i.state); } handleShowAvatarsChange(i: Settings, event: any) { i.state.saveUserSettingsForm.show_avatars = Some(event.target.checked); UserService.Instance.myUserInfo.match({ some: mui => (mui.local_user_view.local_user.show_avatars = event.target.checked), none: void 0, }); i.setState(i.state); } handleBotAccount(i: Settings, event: any) { i.state.saveUserSettingsForm.bot_account = Some(event.target.checked); i.setState(i.state); } handleShowBotAccounts(i: Settings, event: any) { i.state.saveUserSettingsForm.show_bot_accounts = Some(event.target.checked); i.setState(i.state); } handleReadPosts(i: Settings, event: any) { i.state.saveUserSettingsForm.show_read_posts = Some(event.target.checked); i.setState(i.state); } handleShowNewPostNotifs(i: Settings, event: any) { i.state.saveUserSettingsForm.show_new_post_notifs = Some( event.target.checked ); i.setState(i.state); } handleShowScoresChange(i: Settings, event: any) { i.state.saveUserSettingsForm.show_scores = Some(event.target.checked); UserService.Instance.myUserInfo.match({ some: mui => (mui.local_user_view.local_user.show_scores = event.target.checked), none: void 0, }); i.setState(i.state); } handleSendNotificationsToEmailChange(i: Settings, event: any) { i.state.saveUserSettingsForm.send_notifications_to_email = Some( event.target.checked ); i.setState(i.state); } handleThemeChange(i: Settings, event: any) { i.state.saveUserSettingsForm.theme = Some(event.target.value); setTheme(event.target.value, true); i.setState(i.state); } handleInterfaceLangChange(i: Settings, event: any) { i.state.saveUserSettingsForm.interface_language = Some(event.target.value); i18n.changeLanguage( getLanguages(i.state.saveUserSettingsForm.interface_language.unwrap())[0] ); i.setState(i.state); } handleDiscussionLanguageChange(val: number[]) { this.setState( s => ((s.saveUserSettingsForm.discussion_languages = Some(val)), s) ); } handleSortTypeChange(val: SortType) { this.setState( s => ( (s.saveUserSettingsForm.default_sort_type = Some( Object.keys(SortType).indexOf(val) )), s ) ); } handleListingTypeChange(val: ListingType) { this.setState( s => ( (s.saveUserSettingsForm.default_listing_type = Some( Object.keys(ListingType).indexOf(val) )), s ) ); } handleEmailChange(i: Settings, event: any) { i.state.saveUserSettingsForm.email = Some(event.target.value); i.setState(i.state); } handleBioChange(val: string) { this.setState(s => ((s.saveUserSettingsForm.bio = Some(val)), s)); } handleAvatarUpload(url: string) { this.setState(s => ((s.saveUserSettingsForm.avatar = Some(url)), s)); } handleAvatarRemove() { this.setState(s => ((s.saveUserSettingsForm.avatar = Some("")), s)); } handleBannerUpload(url: string) { this.setState(s => ((s.saveUserSettingsForm.banner = Some(url)), s)); } handleBannerRemove() { this.setState(s => ((s.saveUserSettingsForm.banner = Some("")), s)); } handleDisplayNameChange(i: Settings, event: any) { i.state.saveUserSettingsForm.display_name = Some(event.target.value); i.setState(i.state); } handleMatrixUserIdChange(i: Settings, event: any) { i.state.saveUserSettingsForm.matrix_user_id = Some(event.target.value); i.setState(i.state); } handleNewPasswordChange(i: Settings, event: any) { i.state.changePasswordForm.new_password = event.target.value; if (i.state.changePasswordForm.new_password == "") { i.state.changePasswordForm.new_password = undefined; } i.setState(i.state); } handleNewPasswordVerifyChange(i: Settings, event: any) { i.state.changePasswordForm.new_password_verify = event.target.value; if (i.state.changePasswordForm.new_password_verify == "") { i.state.changePasswordForm.new_password_verify = undefined; } i.setState(i.state); } handleOldPasswordChange(i: Settings, event: any) { i.state.changePasswordForm.old_password = event.target.value; if (i.state.changePasswordForm.old_password == "") { i.state.changePasswordForm.old_password = undefined; } i.setState(i.state); } handleSaveSettingsSubmit(i: Settings, event: any) { event.preventDefault(); i.setState({ saveUserSettingsLoading: true }); i.setState(s => ((s.saveUserSettingsForm.auth = auth().unwrap()), s)); let form = new SaveUserSettings({ ...i.state.saveUserSettingsForm }); WebSocketService.Instance.send(wsClient.saveUserSettings(form)); } handleChangePasswordSubmit(i: Settings, event: any) { event.preventDefault(); i.setState({ changePasswordLoading: true }); i.setState(s => ((s.changePasswordForm.auth = auth().unwrap()), s)); let form = new ChangePassword({ ...i.state.changePasswordForm }); WebSocketService.Instance.send(wsClient.changePassword(form)); } handleDeleteAccountShowConfirmToggle(i: Settings, event: any) { event.preventDefault(); i.setState({ deleteAccountShowConfirm: !i.state.deleteAccountShowConfirm }); } handleDeleteAccountPasswordChange(i: Settings, event: any) { i.state.deleteAccountForm.password = event.target.value; i.setState(i.state); } handleDeleteAccount(i: Settings, event: any) { event.preventDefault(); i.setState({ deleteAccountLoading: true }); i.setState(s => ((s.deleteAccountForm.auth = auth().unwrap()), s)); let form = new DeleteAccount({ ...i.state.deleteAccountForm }); WebSocketService.Instance.send(wsClient.deleteAccount(form)); } handleSwitchTab(i: { ctx: Settings; tab: string }) { i.ctx.setState({ currentTab: i.tab }); if (i.ctx.state.currentTab == "blocks") { i.ctx.setupBlockPersonChoices(); i.ctx.setupBlockCommunityChoices(); } } parseMessage(msg: any) { let op = wsUserOp(msg); console.log(msg); if (msg.error) { this.setState({ saveUserSettingsLoading: false, changePasswordLoading: false, deleteAccountLoading: false, }); toast(i18n.t(msg.error), "danger"); return; } else if (op == UserOperation.SaveUserSettings) { let data = wsJsonToRes(msg, LoginResponse); UserService.Instance.login(data); this.setState({ saveUserSettingsLoading: false }); toast(i18n.t("saved")); window.scrollTo(0, 0); } else if (op == UserOperation.ChangePassword) { let data = wsJsonToRes(msg, LoginResponse); UserService.Instance.login(data); this.setState({ changePasswordLoading: false }); window.scrollTo(0, 0); toast(i18n.t("password_changed")); } else if (op == UserOperation.DeleteAccount) { this.setState({ deleteAccountLoading: false, deleteAccountShowConfirm: false, }); UserService.Instance.logout(); window.location.href = "/"; } else if (op == UserOperation.BlockPerson) { let data = wsJsonToRes(msg, BlockPersonResponse); updatePersonBlock(data).match({ some: blocks => this.setState({ personBlocks: blocks }), none: void 0, }); } else if (op == UserOperation.BlockCommunity) { let data = wsJsonToRes( msg, BlockCommunityResponse ); updateCommunityBlock(data).match({ some: blocks => this.setState({ communityBlocks: blocks }), none: void 0, }); } } }