feat: discover people tab, privacy settings, and friend request button fix
- Add "Discover People" section to Add Friend tab with user cards, mutual counts, and inline actions - Add discoverStore for fetching/searching discoverable users across local and federated instances - Add PrivacyPanel to user settings with discoverability toggle - Add is_discoverable column to users table with migration - Fix "Send Friend Request" button vertical alignment using transform centering
This commit is contained in:
@@ -4,10 +4,11 @@ import { useUIStore } from '../../stores/uiStore';
|
||||
import { useAuthStore } from '../../stores/authStore';
|
||||
import { AccountPanel } from './settingsPanels/AccountPanel';
|
||||
import { VoicePanel } from './settingsPanels/VoicePanel';
|
||||
import { PrivacyPanel } from './settingsPanels/PrivacyPanel';
|
||||
import { ConnectionsPanel } from './settingsPanels/ConnectionsPanel';
|
||||
import { InstancePanel } from './settingsPanels/InstancePanel';
|
||||
|
||||
type SettingsTab = 'account' | 'voice' | 'connections' | 'instance';
|
||||
type SettingsTab = 'account' | 'voice' | 'privacy' | 'connections' | 'instance';
|
||||
|
||||
export function UserSettingsModal() {
|
||||
const activeModal = useUIStore((s) => s.activeModal);
|
||||
@@ -24,7 +25,7 @@ export function UserSettingsModal() {
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
const requested = modalData.tab as SettingsTab | undefined;
|
||||
if (requested && ['account', 'voice', 'connections', 'instance'].includes(requested)) {
|
||||
if (requested && ['account', 'voice', 'privacy', 'connections', 'instance'].includes(requested)) {
|
||||
// Only allow instance tab for admins
|
||||
if (requested === 'instance' && !isAdmin) {
|
||||
setTab('account');
|
||||
@@ -59,6 +60,9 @@ export function UserSettingsModal() {
|
||||
<button onClick={() => setTab('voice')} className={tabClass('voice')}>
|
||||
Voice
|
||||
</button>
|
||||
<button onClick={() => setTab('privacy')} className={tabClass('privacy')}>
|
||||
Privacy
|
||||
</button>
|
||||
<button onClick={() => setTab('connections')} className={tabClass('connections')}>
|
||||
Connections
|
||||
</button>
|
||||
@@ -82,6 +86,7 @@ export function UserSettingsModal() {
|
||||
<div className="flex-1 min-w-0 overflow-y-auto scrollbar-thin">
|
||||
{tab === 'account' && <AccountPanel />}
|
||||
{tab === 'voice' && <VoicePanel />}
|
||||
{tab === 'privacy' && <PrivacyPanel />}
|
||||
{tab === 'connections' && <ConnectionsPanel />}
|
||||
{tab === 'instance' && isAdmin && <InstancePanel />}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useAuthStore } from '../../../stores/authStore';
|
||||
import { api } from '../../../api/client';
|
||||
import { Toggle } from '../../ui/Toggle';
|
||||
|
||||
export function PrivacyPanel() {
|
||||
const user = useAuthStore((s) => s.user);
|
||||
const setUser = useAuthStore((s) => s.setUser);
|
||||
const [discoverable, setDiscoverable] = useState(user?.discoverable !== false);
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setDiscoverable(user?.discoverable !== false);
|
||||
}, [user?.discoverable]);
|
||||
|
||||
const handleToggle = async (enabled: boolean) => {
|
||||
setDiscoverable(enabled);
|
||||
setSaving(true);
|
||||
try {
|
||||
const updated = await api.users.update({ discoverable: enabled });
|
||||
setUser(updated);
|
||||
} catch {
|
||||
// Revert on failure
|
||||
setDiscoverable(!enabled);
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-5">
|
||||
<div>
|
||||
<div className="text-[11px] font-semibold text-txt-tertiary uppercase tracking-wider mb-1.5">
|
||||
Discovery
|
||||
</div>
|
||||
<div className="rounded-lg bg-white/[0.03] border border-white/[0.04] p-3.5">
|
||||
<div className="flex items-center justify-between py-1">
|
||||
<div className="flex-1 mr-4">
|
||||
<div className="text-sm text-txt-primary">Allow others to find my profile</div>
|
||||
<div className="text-xs text-txt-tertiary mt-0.5">
|
||||
When enabled, your profile appears in Discover People. Others can always add you by exact username.
|
||||
</div>
|
||||
</div>
|
||||
<Toggle enabled={discoverable} onChange={handleToggle} />
|
||||
</div>
|
||||
{saving && (
|
||||
<div className="text-xs text-txt-tertiary mt-2">Saving...</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user