mirror of
https://gitlab.com/soapbox-pub/mkstack.git
synced 2025-08-27 13:09:22 +00:00
Refactor AppProvider, AppConfig and presetRelays
This commit is contained in:
parent
3ad83cd114
commit
048bf4cc69
@ -27,9 +27,16 @@ const defaultConfig: AppConfig = {
|
||||
relayUrl: "wss://relay.nostr.band",
|
||||
};
|
||||
|
||||
const presetRelays = [
|
||||
{ url: 'wss://ditto.pub/relay', name: 'Ditto' },
|
||||
{ url: 'wss://relay.nostr.band', name: 'Nostr.Band' },
|
||||
{ url: 'wss://relay.damus.io', name: 'Damus' },
|
||||
{ url: 'wss://relay.primal.net', name: 'Primal' },
|
||||
];
|
||||
|
||||
export function App() {
|
||||
return (
|
||||
<AppProvider storageKey="nostr:app-config" defaultConfig={defaultConfig}>
|
||||
<AppProvider storageKey="nostr:app-config" defaultConfig={defaultConfig} presetRelays={presetRelays}>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<NostrLoginProvider storageKey='nostr:login'>
|
||||
<NostrProvider>
|
||||
|
@ -8,13 +8,16 @@ interface AppProviderProps {
|
||||
storageKey: string;
|
||||
/** Default app configuration */
|
||||
defaultConfig: AppConfig;
|
||||
/** Optional list of preset relays to display in the RelaySelector */
|
||||
presetRelays?: { name: string; url: string }[];
|
||||
}
|
||||
|
||||
export function AppProvider(props: AppProviderProps) {
|
||||
const {
|
||||
children,
|
||||
storageKey,
|
||||
defaultConfig
|
||||
defaultConfig,
|
||||
presetRelays,
|
||||
} = props;
|
||||
|
||||
// App configuration state with localStorage persistence
|
||||
@ -28,6 +31,7 @@ export function AppProvider(props: AppProviderProps) {
|
||||
const appContextValue: AppContextType = {
|
||||
config,
|
||||
updateConfig,
|
||||
presetRelays,
|
||||
};
|
||||
|
||||
// Apply theme effects to document
|
||||
|
@ -2,7 +2,7 @@ import React, { useEffect, useRef } from 'react';
|
||||
import { NostrEvent, NPool, NRelay1 } from '@nostrify/nostrify';
|
||||
import { NostrContext } from '@nostrify/react';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useAppConfig } from '@/hooks/useAppConfig';
|
||||
import { useAppContext } from '@/hooks/useAppContext';
|
||||
|
||||
interface NostrProviderProps {
|
||||
children: React.ReactNode;
|
||||
@ -10,7 +10,7 @@ interface NostrProviderProps {
|
||||
|
||||
const NostrProvider: React.FC<NostrProviderProps> = (props) => {
|
||||
const { children } = props;
|
||||
const { config } = useAppConfig();
|
||||
const { config } = useAppContext();
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
|
@ -14,21 +14,22 @@ import {
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { useAppConfig } from "@/hooks/useAppConfig";
|
||||
import { useState } from "react";
|
||||
|
||||
interface RelaySelectorProps {
|
||||
className?: string;
|
||||
availableRelays?: { name: string; url: string }[];
|
||||
selectedRelay?: string;
|
||||
setSelectedRelay: (relay: string) => void;
|
||||
presetRelays?: { name: string; url: string }[];
|
||||
}
|
||||
|
||||
export function RelaySelector({ className, availableRelays = [] }: RelaySelectorProps) {
|
||||
const { config, updateConfig } = useAppConfig();
|
||||
export function RelaySelector(props: RelaySelectorProps) {
|
||||
const { selectedRelay, setSelectedRelay, className, presetRelays = [] } = props;
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [inputValue, setInputValue] = useState("");
|
||||
|
||||
const selectedOption = availableRelays.find((option) => option.url === config.relayUrl);
|
||||
const selectedOption = presetRelays.find((option) => option.url === selectedRelay);
|
||||
|
||||
// Function to normalize relay URL by adding wss:// if no protocol is present
|
||||
const normalizeRelayUrl = (url: string): string => {
|
||||
@ -46,12 +47,9 @@ export function RelaySelector({ className, availableRelays = [] }: RelaySelector
|
||||
|
||||
// Handle adding a custom relay
|
||||
const handleAddCustomRelay = (url: string) => {
|
||||
const normalizedUrl = normalizeRelayUrl(url);
|
||||
if (normalizedUrl) {
|
||||
updateConfig(config => ({ ...config, relayUrl: normalizedUrl }));
|
||||
setSelectedRelay?.(normalizeRelayUrl(url));
|
||||
setOpen(false);
|
||||
setInputValue("");
|
||||
}
|
||||
};
|
||||
|
||||
// Check if input value looks like a valid relay URL
|
||||
@ -83,8 +81,8 @@ export function RelaySelector({ className, availableRelays = [] }: RelaySelector
|
||||
<span className="truncate">
|
||||
{selectedOption
|
||||
? selectedOption.name
|
||||
: config.relayUrl
|
||||
? config.relayUrl.replace(/^wss?:\/\//, '')
|
||||
: selectedRelay
|
||||
? selectedRelay.replace(/^wss?:\/\//, '')
|
||||
: "Select relay..."
|
||||
}
|
||||
</span>
|
||||
@ -121,7 +119,7 @@ export function RelaySelector({ className, availableRelays = [] }: RelaySelector
|
||||
)}
|
||||
</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{availableRelays
|
||||
{presetRelays
|
||||
.filter((option) =>
|
||||
!inputValue ||
|
||||
option.name.toLowerCase().includes(inputValue.toLowerCase()) ||
|
||||
@ -132,7 +130,7 @@ export function RelaySelector({ className, availableRelays = [] }: RelaySelector
|
||||
key={option.url}
|
||||
value={option.url}
|
||||
onSelect={(currentValue) => {
|
||||
updateConfig(config => ({ ...config, relayUrl: currentValue }));
|
||||
setSelectedRelay(normalizeRelayUrl(currentValue));
|
||||
setOpen(false);
|
||||
setInputValue("");
|
||||
}}
|
||||
@ -140,7 +138,7 @@ export function RelaySelector({ className, availableRelays = [] }: RelaySelector
|
||||
<Check
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4",
|
||||
config.relayUrl === option.url ? "opacity-100" : "opacity-0"
|
||||
selectedRelay === option.url ? "opacity-100" : "opacity-0"
|
||||
)}
|
||||
/>
|
||||
<div className="flex flex-col">
|
||||
|
@ -12,6 +12,7 @@ import {
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar.tsx';
|
||||
import { RelaySelector } from '@/components/RelaySelector';
|
||||
import { useLoggedInAccounts, type Account } from '@/hooks/useLoggedInAccounts';
|
||||
import { useAppContext } from '@/hooks/useAppContext';
|
||||
import { genUserName } from '@/lib/genUserName';
|
||||
|
||||
interface AccountSwitcherProps {
|
||||
@ -19,11 +20,14 @@ interface AccountSwitcherProps {
|
||||
}
|
||||
|
||||
export function AccountSwitcher({ onAddAccountClick }: AccountSwitcherProps) {
|
||||
const { config, updateConfig, presetRelays } = useAppContext();
|
||||
const { currentUser, otherUsers, setLogin, removeLogin } = useLoggedInAccounts();
|
||||
|
||||
if (!currentUser) return null;
|
||||
|
||||
const getDisplayName = (account: Account): string => account.metadata.name ?? genUserName(account.pubkey);
|
||||
const getDisplayName = (account: Account): string => {
|
||||
return account.metadata.name ?? genUserName(account.pubkey);
|
||||
}
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
@ -41,7 +45,12 @@ export function AccountSwitcher({ onAddAccountClick }: AccountSwitcherProps) {
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className='w-56 p-2 animate-scale-in'>
|
||||
<div className='font-medium text-sm px-2 py-1.5'>Switch Relay</div>
|
||||
<RelaySelector className="w-full" />
|
||||
<RelaySelector
|
||||
className="w-full"
|
||||
selectedRelay={config.relayUrl}
|
||||
setSelectedRelay={(relayUrl) => updateConfig((config) => ({ ...config, relayUrl }))}
|
||||
presetRelays={presetRelays}
|
||||
/>
|
||||
<DropdownMenuSeparator />
|
||||
<div className='font-medium text-sm px-2 py-1.5'>Switch Account</div>
|
||||
{otherUsers.map((user) => (
|
||||
|
@ -14,6 +14,8 @@ export interface AppContextType {
|
||||
config: AppConfig;
|
||||
/** Update configuration using a callback that receives current config and returns new config */
|
||||
updateConfig: (updater: (currentConfig: AppConfig) => AppConfig) => void;
|
||||
/** Optional list of preset relays to display in the RelaySelector */
|
||||
presetRelays?: { name: string; url: string }[];
|
||||
}
|
||||
|
||||
export const AppContext = createContext<AppContextType | undefined>(undefined);
|
||||
|
@ -5,10 +5,10 @@ import { AppContext, type AppContextType } from "@/contexts/AppContext";
|
||||
* Hook to access and update application configuration
|
||||
* @returns Application context with config and update methods
|
||||
*/
|
||||
export function useAppConfig(): AppContextType {
|
||||
export function useAppContext(): AppContextType {
|
||||
const context = useContext(AppContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('useAppConfig must be used within an AppProvider');
|
||||
throw new Error('useAppContext must be used within an AppProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
import { type Theme } from "@/contexts/AppContext";
|
||||
import { useAppConfig } from "@/hooks/useAppConfig";
|
||||
import { useAppContext } from "@/hooks/useAppContext";
|
||||
|
||||
/**
|
||||
* Hook to get and set the active theme
|
||||
* @returns Theme context with theme and setTheme
|
||||
*/
|
||||
export function useTheme(): { theme: Theme; setTheme: (theme: Theme) => void } {
|
||||
const { config, updateConfig } = useAppConfig();
|
||||
const { config, updateConfig } = useAppContext();
|
||||
|
||||
return {
|
||||
theme: config.theme,
|
||||
|
Loading…
x
Reference in New Issue
Block a user