Refactor SupabaseSettingsForm component
The SupabaseSettingsForm component was refactored into smaller, more manageable components to improve readability and maintainability.
This commit is contained in:
39
src/components/supabase/CorsProxyToggle.tsx
Normal file
39
src/components/supabase/CorsProxyToggle.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
import React from 'react';
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Shield } from "lucide-react";
|
||||
|
||||
interface CorsProxyToggleProps {
|
||||
useProxy: boolean;
|
||||
setUseProxy: (use: boolean) => void;
|
||||
}
|
||||
|
||||
const CorsProxyToggle: React.FC<CorsProxyToggleProps> = ({
|
||||
useProxy,
|
||||
setUseProxy
|
||||
}) => {
|
||||
return (
|
||||
<div className="flex items-center justify-between space-x-2 py-2">
|
||||
<div className="space-y-0.5">
|
||||
<Label htmlFor="cors-proxy" className="cursor-pointer">
|
||||
<div className="flex items-center">
|
||||
<Shield className="h-4 w-4 mr-2 text-neuro-income" />
|
||||
<span>CORS 프록시 사용</span>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500">
|
||||
HTTP URL에 접근 문제가 있는 경우 활성화하세요
|
||||
</p>
|
||||
</Label>
|
||||
</div>
|
||||
<Switch
|
||||
id="cors-proxy"
|
||||
checked={useProxy}
|
||||
onCheckedChange={setUseProxy}
|
||||
className="data-[state=checked]:bg-neuro-income"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CorsProxyToggle;
|
||||
36
src/components/supabase/ProxyTypeSelector.tsx
Normal file
36
src/components/supabase/ProxyTypeSelector.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
import React from 'react';
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
|
||||
interface ProxyTypeSelectorProps {
|
||||
proxyType: string;
|
||||
setProxyType: (type: string) => void;
|
||||
}
|
||||
|
||||
const ProxyTypeSelector: React.FC<ProxyTypeSelectorProps> = ({
|
||||
proxyType,
|
||||
setProxyType
|
||||
}) => {
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="proxy-type" className="text-base">프록시 서비스 선택</Label>
|
||||
<Select value={proxyType} onValueChange={setProxyType}>
|
||||
<SelectTrigger id="proxy-type" className="w-full">
|
||||
<SelectValue placeholder="프록시 서비스 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="corsproxy.io">corsproxy.io (기본)</SelectItem>
|
||||
<SelectItem value="thingproxy">thingproxy.freeboard.io</SelectItem>
|
||||
<SelectItem value="allorigins">allorigins.win</SelectItem>
|
||||
<SelectItem value="cors-anywhere">cors-anywhere.herokuapp.com</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p className="text-xs text-gray-500 mt-1">
|
||||
특정 프록시 서비스가 작동하지 않으면 다른 서비스를 시도해보세요.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProxyTypeSelector;
|
||||
36
src/components/supabase/SaveSettingsButton.tsx
Normal file
36
src/components/supabase/SaveSettingsButton.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
import React from 'react';
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Save, RefreshCw } from "lucide-react";
|
||||
|
||||
interface SaveSettingsButtonProps {
|
||||
onClick: () => void;
|
||||
isSaving: boolean;
|
||||
}
|
||||
|
||||
const SaveSettingsButton: React.FC<SaveSettingsButtonProps> = ({
|
||||
onClick,
|
||||
isSaving
|
||||
}) => {
|
||||
return (
|
||||
<Button
|
||||
onClick={onClick}
|
||||
disabled={isSaving}
|
||||
className="w-full bg-neuro-income text-white"
|
||||
>
|
||||
{isSaving ? (
|
||||
<>
|
||||
<RefreshCw className="mr-2 h-4 w-4 animate-spin" />
|
||||
저장 중...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Save className="mr-2 h-4 w-4" />
|
||||
설정 저장
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default SaveSettingsButton;
|
||||
40
src/components/supabase/SupabaseKeyInput.tsx
Normal file
40
src/components/supabase/SupabaseKeyInput.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
import React from 'react';
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
|
||||
interface SupabaseKeyInputProps {
|
||||
supabaseKey: string;
|
||||
setSupabaseKey: (key: string) => void;
|
||||
}
|
||||
|
||||
const SupabaseKeyInput: React.FC<SupabaseKeyInputProps> = ({
|
||||
supabaseKey,
|
||||
setSupabaseKey
|
||||
}) => {
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="supabase-key" className="text-base">Supabase Anon Key</Label>
|
||||
<div className="relative">
|
||||
<svg
|
||||
className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-500 h-5 w-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" />
|
||||
</svg>
|
||||
<Input
|
||||
id="supabase-key"
|
||||
placeholder="your-anon-key"
|
||||
value={supabaseKey}
|
||||
onChange={(e) => setSupabaseKey(e.target.value)}
|
||||
className="pl-10 neuro-pressed"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SupabaseKeyInput;
|
||||
@@ -1,17 +1,18 @@
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { DatabaseIcon, Save, RefreshCw, Shield, AlertTriangle, Check } from "lucide-react";
|
||||
import { toast } from "@/hooks/useToast.wrapper";
|
||||
import {
|
||||
configureSupabase,
|
||||
isCorsProxyEnabled,
|
||||
getProxyType
|
||||
} from "@/lib/supabase/config";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
|
||||
// 분리된 컴포넌트들 임포트
|
||||
import SupabaseUrlInput from './SupabaseUrlInput';
|
||||
import SupabaseKeyInput from './SupabaseKeyInput';
|
||||
import CorsProxyToggle from './CorsProxyToggle';
|
||||
import ProxyTypeSelector from './ProxyTypeSelector';
|
||||
import SaveSettingsButton from './SaveSettingsButton';
|
||||
|
||||
interface SupabaseSettingsFormProps {
|
||||
onSaved: () => void;
|
||||
@@ -84,121 +85,35 @@ const SupabaseSettingsForm: React.FC<SupabaseSettingsFormProps> = ({ onSaved })
|
||||
}
|
||||
};
|
||||
|
||||
const isHttpsUrl = supabaseUrl.startsWith("https://");
|
||||
const suggestProxy = supabaseUrl.startsWith("http://") && !useProxy;
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="supabase-url" className="text-base">Supabase URL</Label>
|
||||
<div className="relative">
|
||||
<DatabaseIcon className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-500 h-5 w-5" />
|
||||
<Input
|
||||
id="supabase-url"
|
||||
placeholder="http://your-supabase-url.com"
|
||||
value={supabaseUrl}
|
||||
onChange={(e) => setSupabaseUrl(e.target.value)}
|
||||
className="pl-10 neuro-pressed"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* URL 관련 경고 및 안내 추가 */}
|
||||
{suggestProxy && (
|
||||
<div className="flex items-center text-amber-500 text-xs mt-1 p-2 bg-amber-50 rounded-md">
|
||||
<AlertTriangle className="h-4 w-4 mr-1 flex-shrink-0" />
|
||||
<span>HTTP URL을 사용하고 계십니다. CORS 프록시 활성화를 권장합니다.</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isHttpsUrl && (
|
||||
<div className="flex items-center text-green-500 text-xs mt-1 p-2 bg-green-50 rounded-md">
|
||||
<Check className="h-4 w-4 mr-1 flex-shrink-0" />
|
||||
<span>HTTPS URL을 사용하고 있습니다. 권장됩니다.</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<SupabaseUrlInput
|
||||
supabaseUrl={supabaseUrl}
|
||||
setSupabaseUrl={setSupabaseUrl}
|
||||
useProxy={useProxy}
|
||||
/>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="supabase-key" className="text-base">Supabase Anon Key</Label>
|
||||
<div className="relative">
|
||||
<svg
|
||||
className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-500 h-5 w-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" />
|
||||
</svg>
|
||||
<Input
|
||||
id="supabase-key"
|
||||
placeholder="your-anon-key"
|
||||
value={supabaseKey}
|
||||
onChange={(e) => setSupabaseKey(e.target.value)}
|
||||
className="pl-10 neuro-pressed"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<SupabaseKeyInput
|
||||
supabaseKey={supabaseKey}
|
||||
setSupabaseKey={setSupabaseKey}
|
||||
/>
|
||||
|
||||
{/* CORS 프록시 설정 추가 */}
|
||||
<div className="flex items-center justify-between space-x-2 py-2">
|
||||
<div className="space-y-0.5">
|
||||
<Label htmlFor="cors-proxy" className="cursor-pointer">
|
||||
<div className="flex items-center">
|
||||
<Shield className="h-4 w-4 mr-2 text-neuro-income" />
|
||||
<span>CORS 프록시 사용</span>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500">
|
||||
HTTP URL에 접근 문제가 있는 경우 활성화하세요
|
||||
</p>
|
||||
</Label>
|
||||
</div>
|
||||
<Switch
|
||||
id="cors-proxy"
|
||||
checked={useProxy}
|
||||
onCheckedChange={setUseProxy}
|
||||
className="data-[state=checked]:bg-neuro-income"
|
||||
/>
|
||||
</div>
|
||||
<CorsProxyToggle
|
||||
useProxy={useProxy}
|
||||
setUseProxy={setUseProxy}
|
||||
/>
|
||||
|
||||
{/* 프록시 서비스 선택 옵션 추가 */}
|
||||
{useProxy && (
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="proxy-type" className="text-base">프록시 서비스 선택</Label>
|
||||
<Select value={proxyType} onValueChange={setProxyType}>
|
||||
<SelectTrigger id="proxy-type" className="w-full">
|
||||
<SelectValue placeholder="프록시 서비스 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="corsproxy.io">corsproxy.io (기본)</SelectItem>
|
||||
<SelectItem value="thingproxy">thingproxy.freeboard.io</SelectItem>
|
||||
<SelectItem value="allorigins">allorigins.win</SelectItem>
|
||||
<SelectItem value="cors-anywhere">cors-anywhere.herokuapp.com</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p className="text-xs text-gray-500 mt-1">
|
||||
특정 프록시 서비스가 작동하지 않으면 다른 서비스를 시도해보세요.
|
||||
</p>
|
||||
</div>
|
||||
<ProxyTypeSelector
|
||||
proxyType={proxyType}
|
||||
setProxyType={setProxyType}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Button
|
||||
onClick={handleSave}
|
||||
disabled={isSaving}
|
||||
className="w-full bg-neuro-income text-white"
|
||||
>
|
||||
{isSaving ? (
|
||||
<>
|
||||
<RefreshCw className="mr-2 h-4 w-4 animate-spin" />
|
||||
저장 중...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Save className="mr-2 h-4 w-4" />
|
||||
설정 저장
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
<SaveSettingsButton
|
||||
onClick={handleSave}
|
||||
isSaving={isSaving}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
53
src/components/supabase/SupabaseUrlInput.tsx
Normal file
53
src/components/supabase/SupabaseUrlInput.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
|
||||
import React from 'react';
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { DatabaseIcon, AlertTriangle, Check } from "lucide-react";
|
||||
|
||||
interface SupabaseUrlInputProps {
|
||||
supabaseUrl: string;
|
||||
setSupabaseUrl: (url: string) => void;
|
||||
useProxy: boolean;
|
||||
}
|
||||
|
||||
const SupabaseUrlInput: React.FC<SupabaseUrlInputProps> = ({
|
||||
supabaseUrl,
|
||||
setSupabaseUrl,
|
||||
useProxy
|
||||
}) => {
|
||||
const isHttpsUrl = supabaseUrl.startsWith("https://");
|
||||
const suggestProxy = supabaseUrl.startsWith("http://") && !useProxy;
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="supabase-url" className="text-base">Supabase URL</Label>
|
||||
<div className="relative">
|
||||
<DatabaseIcon className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-500 h-5 w-5" />
|
||||
<Input
|
||||
id="supabase-url"
|
||||
placeholder="http://your-supabase-url.com"
|
||||
value={supabaseUrl}
|
||||
onChange={(e) => setSupabaseUrl(e.target.value)}
|
||||
className="pl-10 neuro-pressed"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* URL 관련 경고 및 안내 추가 */}
|
||||
{suggestProxy && (
|
||||
<div className="flex items-center text-amber-500 text-xs mt-1 p-2 bg-amber-50 rounded-md">
|
||||
<AlertTriangle className="h-4 w-4 mr-1 flex-shrink-0" />
|
||||
<span>HTTP URL을 사용하고 계십니다. CORS 프록시 활성화를 권장합니다.</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isHttpsUrl && (
|
||||
<div className="flex items-center text-green-500 text-xs mt-1 p-2 bg-green-50 rounded-md">
|
||||
<Check className="h-4 w-4 mr-1 flex-shrink-0" />
|
||||
<span>HTTPS URL을 사용하고 있습니다. 권장됩니다.</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SupabaseUrlInput;
|
||||
Reference in New Issue
Block a user