mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-20 22:16:26 +00:00
refactor(settings): photo provider cards read their state from the shared hook
With the badge and toast options gone from usePhotoProviderConnections, the desktop and phone cards called the hook identically and then derived the same seven per card values (fields, config, values, badge, testing, whether save and test have a route) line for line, which lint:dup counts as a copied block of 25 lines in MPhotoProvidersSection.tsx. The hook now hands each card those values through providerCard, and both views keep only their markup. Nothing the user sees changes. New test FE-COMP-PHOTOCONN-011 covers providerCard. No existing assertion changed.
This commit is contained in:
@@ -7,21 +7,14 @@ import { SETTINGS_BUTTON, SETTINGS_BUTTON_PRIMARY, SettingRow, SettingRows, Stat
|
||||
import { EditorField, INPUT } from '../shared/dialogParts'
|
||||
import { fs } from '../shared/DialogShell'
|
||||
import { Tooltip } from '../shared/Tooltip'
|
||||
import {
|
||||
getProviderConfig,
|
||||
getProviderFields,
|
||||
usePhotoProviderConnections,
|
||||
type PhotoProviderAddon,
|
||||
} from './usePhotoProviderConnections'
|
||||
import { usePhotoProviderConnections, type PhotoProviderAddon } from './usePhotoProviderConnections'
|
||||
|
||||
export default function PhotoProvidersSection(): React.ReactElement {
|
||||
const { t } = useTranslation()
|
||||
const {
|
||||
memoriesEnabled,
|
||||
activePhotoProviders,
|
||||
providerValues,
|
||||
providerConnected,
|
||||
providerTesting,
|
||||
providerCard,
|
||||
saving,
|
||||
handleProviderFieldChange,
|
||||
isProviderSaveDisabled,
|
||||
@@ -30,13 +23,7 @@ export default function PhotoProvidersSection(): React.ReactElement {
|
||||
} = usePhotoProviderConnections()
|
||||
|
||||
const renderPhotoProviderSection = (provider: PhotoProviderAddon): React.ReactElement => {
|
||||
const fields = getProviderFields(provider)
|
||||
const cfg = getProviderConfig(provider)
|
||||
const values = providerValues[provider.id] || {}
|
||||
const connected = !!providerConnected[provider.id]
|
||||
const testing = !!providerTesting[provider.id]
|
||||
const canSave = !!cfg.settings_put
|
||||
const canTest = !!(cfg.test_post || cfg.test_get || cfg.status_get)
|
||||
const { fields, values, connected, testing, canSave, canTest } = providerCard(provider)
|
||||
|
||||
const saveDisabledReason = !canSave
|
||||
? t('memories.saveRouteNotConfigured')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// FE-COMP-PHOTOCONN-001 to -010: the photo provider connection logic both settings shells share.
|
||||
// FE-COMP-PHOTOCONN-001 to -011: the photo provider connection logic both settings shells share.
|
||||
import { act, renderHook, waitFor } from '@testing-library/react';
|
||||
import { resetAllStores, seedStore } from '../../../tests/helpers/store';
|
||||
import apiClient from '../../api/client';
|
||||
@@ -227,4 +227,20 @@ describe('usePhotoProviderConnections', () => {
|
||||
await act(() => desktop.result.current.handleTestProvider(PROVIDER));
|
||||
expect(toast.error).toHaveBeenLastCalledWith('memories.connectionError(Immich)');
|
||||
});
|
||||
|
||||
it('FE-COMP-PHOTOCONN-011: providerCard hands each card its fields, values, badge and working buttons', async () => {
|
||||
seedProviders([PROVIDER]);
|
||||
stubGets({
|
||||
'/addons/immich/settings': { data: { url: 'https://a' } },
|
||||
'/addons/immich/status': { data: { connected: true } },
|
||||
});
|
||||
const { result } = render();
|
||||
await waitFor(() => expect(result.current.providerCard(PROVIDER).connected).toBe(true));
|
||||
const card = result.current.providerCard(PROVIDER);
|
||||
expect(card.fields.map((f) => f.key)).toEqual(['url', 'api_key', 'shared']);
|
||||
expect(card.values).toEqual({ url: 'https://a', shared: 'false' });
|
||||
expect(card).toMatchObject({ testing: false, canSave: true, canTest: true });
|
||||
const bare = result.current.providerCard({ ...PROVIDER, id: 'other', config: {} });
|
||||
expect(bare).toMatchObject({ values: {}, connected: false, canSave: false, canTest: false });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -221,9 +221,23 @@ export function usePhotoProviderConnections() {
|
||||
}
|
||||
};
|
||||
|
||||
/** What one provider card draws from: its fields, values, badge and which buttons work. */
|
||||
const providerCard = (provider: PhotoProviderAddon) => {
|
||||
const cfg = getProviderConfig(provider);
|
||||
return {
|
||||
fields: getProviderFields(provider),
|
||||
values: providerValues[provider.id] || {},
|
||||
connected: !!providerConnected[provider.id],
|
||||
testing: !!providerTesting[provider.id],
|
||||
canSave: !!cfg.settings_put,
|
||||
canTest: !!(cfg.test_post || cfg.test_get || cfg.status_get),
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
memoriesEnabled,
|
||||
activePhotoProviders,
|
||||
providerCard,
|
||||
providerValues,
|
||||
providerConnected,
|
||||
providerTesting,
|
||||
|
||||
@@ -3,12 +3,7 @@ import { Camera, Save, RefreshCw } from 'lucide-react'
|
||||
import { useTranslation } from '../../../i18n'
|
||||
import { MSetCard, MSetEyebrow, MSetRow, MSetInput, MSetButton, MSetHint } from './MSettingsUi'
|
||||
import MToggle from '../../components/MToggle'
|
||||
import {
|
||||
getProviderConfig,
|
||||
getProviderFields,
|
||||
usePhotoProviderConnections,
|
||||
type PhotoProviderAddon,
|
||||
} from '../../../components/Settings/usePhotoProviderConnections'
|
||||
import { usePhotoProviderConnections, type PhotoProviderAddon } from '../../../components/Settings/usePhotoProviderConnections'
|
||||
|
||||
/**
|
||||
* Mobile-native twin of components/Settings/PhotoProvidersSection. Same logic
|
||||
@@ -22,9 +17,7 @@ export default function MPhotoProvidersSection(): React.ReactElement {
|
||||
const {
|
||||
memoriesEnabled,
|
||||
activePhotoProviders,
|
||||
providerValues,
|
||||
providerConnected,
|
||||
providerTesting,
|
||||
providerCard,
|
||||
saving,
|
||||
handleProviderFieldChange,
|
||||
isProviderSaveDisabled,
|
||||
@@ -33,13 +26,7 @@ export default function MPhotoProvidersSection(): React.ReactElement {
|
||||
} = usePhotoProviderConnections()
|
||||
|
||||
const renderPhotoProviderSection = (provider: PhotoProviderAddon): React.ReactElement => {
|
||||
const fields = getProviderFields(provider)
|
||||
const cfg = getProviderConfig(provider)
|
||||
const values = providerValues[provider.id] || {}
|
||||
const connected = !!providerConnected[provider.id]
|
||||
const testing = !!providerTesting[provider.id]
|
||||
const canSave = !!cfg.settings_put
|
||||
const canTest = !!(cfg.test_post || cfg.test_get || cfg.status_get)
|
||||
const { fields, values, connected, testing, canSave, canTest } = providerCard(provider)
|
||||
|
||||
return (
|
||||
<MSetCard key={provider.id} title={provider.name || provider.id} icon={Camera} className="mt-3 first:mt-0">
|
||||
|
||||
Reference in New Issue
Block a user