diff --git a/src/app/features/settings/account/ExternalConnections.tsx b/src/app/features/settings/account/ExternalConnections.tsx new file mode 100644 index 000000000..202b5f5e7 --- /dev/null +++ b/src/app/features/settings/account/ExternalConnections.tsx @@ -0,0 +1,42 @@ +import { SequenceCard } from '$components/sequence-card'; +import { useMatrixClient } from '$hooks/useMatrixClient'; +import { UserProfile } from '$hooks/useUserProfile'; +import { profilesCacheAtom } from '$state/userRoomProfile'; +import { Box, Text } from 'folds'; +import { useSetAtom } from 'jotai'; +import { useCallback } from 'react'; +import { SequenceCardStyle } from '../styles.css'; +import { ExternalListenbrainzConnectionEditor } from './ExternalListenbrainzConnection'; + +type ExternalConnectionsProps = { + profile: UserProfile; + userId: string; +}; +export function ExternalConnectionsEditor({ profile, userId }: ExternalConnectionsProps) { + const mx = useMatrixClient(); + const setGlobalProfiles = useSetAtom(profilesCacheAtom); + + const handleSaveField = useCallback( + async (key: string, value: any) => { + await mx.setExtendedProfileProperty?.(key, value); + setGlobalProfiles((prev) => { + const newCache = { ...prev }; + delete newCache[userId]; + return newCache; + }); + }, + [mx, userId, setGlobalProfiles] + ); + + return ( + + External Connections + + handleSaveField('fyi.cisnt.external.listenbrainz', con)} + /> + + + ); +} diff --git a/src/app/features/settings/account/ExternalListenbrainzConnection.tsx b/src/app/features/settings/account/ExternalListenbrainzConnection.tsx new file mode 100644 index 000000000..9f74d9b1a --- /dev/null +++ b/src/app/features/settings/account/ExternalListenbrainzConnection.tsx @@ -0,0 +1,49 @@ +import { SettingTile } from '$components/setting-tile'; +import { ExternalListenbrainzConnection } from '$hooks/useUserProfile'; +import { Input } from 'folds'; +import { useState, useEffect, ChangeEvent } from 'react'; + +export type ExternalListenbrainzConnectionProps = { + current?: ExternalListenbrainzConnection; + onSave: (p: ExternalListenbrainzConnection) => void; +}; + +export function ExternalListenbrainzConnectionEditor({ + current, + onSave, +}: ExternalListenbrainzConnectionProps) { + const initialString = current?.username ? `@${current.username}` : ''; + const [val, setVal] = useState(initialString); + + useEffect(() => setVal(initialString), [initialString]); + + const handleSave = () => { + if (val === initialString) return; + onSave({ username: val.replace('@', ''), v: 1 }); + }; + + const handleChange = (e: ChangeEvent) => { + setVal(e.currentTarget.value); + }; + + return ( + e.key === 'Enter' && handleSave()} + style={{ width: '232px' }} + /> + } + /> + ); +} diff --git a/src/app/features/settings/account/Profile.tsx b/src/app/features/settings/account/Profile.tsx index 85bf0bc37..6127ca930 100644 --- a/src/app/features/settings/account/Profile.tsx +++ b/src/app/features/settings/account/Profile.tsx @@ -54,6 +54,7 @@ import { PronounEditor } from './PronounEditor'; import { BioEditor } from './BioEditor'; import { NameColorEditor } from './NameColorEditor'; import { StatusEditor } from './StatusEditor'; +import { ExternalConnectionsEditor } from './ExternalConnections'; type PronounSet = { summary: string; @@ -735,6 +736,7 @@ export function Profile() { + ); } diff --git a/src/app/hooks/useUserProfile.ts b/src/app/hooks/useUserProfile.ts index e5f1a013a..7b684d7ba 100644 --- a/src/app/hooks/useUserProfile.ts +++ b/src/app/hooks/useUserProfile.ts @@ -11,6 +11,11 @@ import { useMatrixClient } from './useMatrixClient'; const inFlightProfiles = new Map>(); +export type ExternalListenbrainzConnection = { + username?: string; + v?: number; +}; + export type UserProfile = { avatarUrl?: string; displayName?: string; @@ -22,6 +27,7 @@ export type UserProfile = { nameColor?: string; isCat?: boolean; hasCats?: boolean; + listenBrainzAccount?: ExternalListenbrainzConnection; extended?: Record; _fetched?: boolean; }; @@ -40,6 +46,8 @@ const normalizeInfo = (info: any): UserProfile => { 'moe.sable.app.name_color', 'kitty.meow.has_cats', 'kitty.meow.is_cat', + // listenbrainz linking + 'fyi.cisnt.external.listenbrainz', ]; const extended: Record = {}; @@ -60,6 +68,7 @@ const normalizeInfo = (info: any): UserProfile => { nameColor: info['moe.sable.app.name_color'], isCat: info['kitty.meow.is_cat'] === true, hasCats: info['kitty.meow.has_cats'] === true, + listenBrainzAccount: info['fyi.cisnt.external.listenbrainz'], extended, _fetched: true, };