Allow manual version info edit

Make the version info card editable via text boxes.
This commit is contained in:
gpt-engineer-app[bot]
2025-03-18 14:24:10 +00:00
parent 450e57fe50
commit 73ff9e7886
3 changed files with 134 additions and 60 deletions

View File

@@ -1,5 +1,7 @@
{ {
"versionCode": 1, "versionCode": 1,
"versionName": "1.0.0", "versionName": "1.0.0",
"buildNumber": 1 "buildNumber": 1,
"notes": "사용자가 수정한 버전 정보입니다. 이 파일을 편집하여 앱 버전 정보를 변경할 수 있습니다."
} }

View File

@@ -1,14 +1,20 @@
import React, { useCallback, useEffect, useState, useRef } from 'react'; import React, { useCallback, useEffect, useState, useRef } from 'react';
import { getAppVersionInfo, isAndroidPlatform } from '@/utils/platform'; import { getAppVersionInfo, isAndroidPlatform } from '@/utils/platform';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
interface AppVersionInfoProps { interface AppVersionInfoProps {
className?: string; className?: string;
showDevInfo?: boolean; // 개발자 정보 표시 여부 showDevInfo?: boolean; // 개발자 정보 표시 여부
editable?: boolean; // 편집 가능 여부
} }
const AppVersionInfo: React.FC<AppVersionInfoProps> = ({ const AppVersionInfo: React.FC<AppVersionInfoProps> = ({
className, className,
showDevInfo = true showDevInfo = true,
editable = false
}) => { }) => {
const [versionInfo, setVersionInfo] = useState<{ const [versionInfo, setVersionInfo] = useState<{
versionName: string; versionName: string;
@@ -23,42 +29,56 @@ const AppVersionInfo: React.FC<AppVersionInfoProps> = ({
const [error, setError] = useState(false); const [error, setError] = useState(false);
const [retries, setRetries] = useState(0); const [retries, setRetries] = useState(0);
// 편집 가능한 필드를 위한 상태
const [editableVersionName, setEditableVersionName] = useState('1.0.0');
const [editableBuildNumber, setEditableBuildNumber] = useState('1');
const [editableVersionCode, setEditableVersionCode] = useState('1');
// 버전 정보 가져오기 // 버전 정보 가져오기
const fetchVersionInfo = useCallback(async () => { const fetchVersionInfo = useCallback(async () => {
setLoading(true); if (!editable) {
setError(false); setLoading(true);
setError(false);
try { try {
console.log('앱 버전 정보 요청 시작... (retries:', retries, ')'); console.log('앱 버전 정보 요청 시작... (retries:', retries, ')');
console.log('현재 플랫폼은', isAndroidPlatform() ? 'Android' : '기타'); console.log('현재 플랫폼은', isAndroidPlatform() ? 'Android' : '기타');
// 재시도를 하는 경우 짤은 지연 추가 // 재시도를 하는 경우 짤은 지연 추가
if (retries > 0) { if (retries > 0) {
await new Promise(resolve => setTimeout(resolve, 300)); await new Promise(resolve => setTimeout(resolve, 300));
}
const info = await getAppVersionInfo();
console.log('받은 앱 버전 정보:', info);
// 데이터 검증 - 유효한 버전 정보인지 확인
if (!info || typeof info !== 'object') {
throw new Error('유효하지 않은 응답 형식');
}
setVersionInfo({
versionName: info.versionName,
buildNumber: info.buildNumber,
versionCode: info.versionCode
});
// 편집 가능한 필드도 업데이트
setEditableVersionName(info.versionName);
setEditableBuildNumber(String(info.buildNumber));
if (info.versionCode) {
setEditableVersionCode(String(info.versionCode));
}
setLoading(false);
console.log('앱 버전 정보 표시 준비 완료');
} catch (error) {
console.error('버전 정보 가져오기 실패:', error);
setError(true);
setLoading(false);
} }
const info = await getAppVersionInfo();
console.log('받은 앱 버전 정보:', info);
// 데이터 검증 - 유효한 버전 정보인지 확인
if (!info || typeof info !== 'object') {
throw new Error('유효하지 않은 응답 형식');
}
setVersionInfo({
versionName: info.versionName,
buildNumber: info.buildNumber,
versionCode: info.versionCode
});
setLoading(false);
console.log('앱 버전 정보 표시 준비 완료');
} catch (error) {
console.error('버전 정보 가져오기 실패:', error);
setError(true);
setLoading(false);
} }
}, [retries]); }, [retries, editable]);
// 재시도 처리 // 재시도 처리
const handleRetry = useCallback(() => { const handleRetry = useCallback(() => {
@@ -71,28 +91,81 @@ const AppVersionInfo: React.FC<AppVersionInfoProps> = ({
// 컴포넌트 마운트 시 즉시 실행 (IIFE) // 컴포넌트 마운트 시 즉시 실행 (IIFE)
useEffect(() => { useEffect(() => {
(async () => { if (!editable) {
// 즉시 버전 정보 가져오기 시도 (async () => {
await fetchVersionInfo(); // 즉시 버전 정보 가져오기 시도
await fetchVersionInfo();
// 300ms 후에 한번 더 시도 (네이티브 플러그인이 완전히 로드되지 않았을 경우 대비) // 300ms 후에 한번 더 시도 (네이티브 플러그인이 완전히 로드되지 않았을 경우 대비)
setTimeout(() => { setTimeout(() => {
if (error || loading) { if (error || loading) {
fetchVersionInfo();
initialLoadAttemptedRef.current = true;
}
}, 1000);
})();
// 개발 모드에서는 버전 정보 변경을 쉽게 확인하기 위해 주기적 갱신
if (process.env.NODE_ENV === 'development') {
const interval = setInterval(() => {
fetchVersionInfo(); fetchVersionInfo();
initialLoadAttemptedRef.current = true; }, 30000); // 30초마다 새로 가져오기
}
}, 1000);
})();
// 개발 모드에서는 버전 정보 변경을 쉽게 확인하기 위해 주기적 갱신 return () => clearInterval(interval);
if (process.env.NODE_ENV === 'development') { }
const interval = setInterval(() => {
fetchVersionInfo();
}, 30000); // 30초마다 새로 가져오기
return () => clearInterval(interval);
} }
}, [fetchVersionInfo, error, loading]); }, [fetchVersionInfo, error, loading, editable]);
if (editable) {
return (
<div className={className}>
<div className="space-y-3">
<div>
<Label htmlFor="versionName"> </Label>
<Input
id="versionName"
value={editableVersionName}
onChange={(e) => setEditableVersionName(e.target.value)}
placeholder="앱 버전 (예: 1.0.0)"
/>
</div>
<div>
<Label htmlFor="buildNumber"> </Label>
<Input
id="buildNumber"
value={editableBuildNumber}
onChange={(e) => setEditableBuildNumber(e.target.value)}
placeholder="빌드 번호 (예: 1)"
type="number"
/>
</div>
{showDevInfo && (
<div>
<Label htmlFor="versionCode"> </Label>
<Input
id="versionCode"
value={editableVersionCode}
onChange={(e) => setEditableVersionCode(e.target.value)}
placeholder="버전 코드 (예: 1)"
type="number"
/>
</div>
)}
<div>
<Label htmlFor="notes"></Label>
<Textarea
id="notes"
placeholder="추가 정보를 입력하세요"
className="h-20"
/>
</div>
</div>
</div>
);
}
return ( return (
<div className={className}> <div className={className}>

View File

@@ -83,7 +83,6 @@ const Settings = () => {
{/* Data Sync Settings */} {/* Data Sync Settings */}
<div className="mb-8"> <div className="mb-8">
<SyncSettings /> <SyncSettings />
</div> </div>
@@ -97,9 +96,7 @@ const Settings = () => {
<div className="space-y-4 mb-8"> <div className="space-y-4 mb-8">
<h2 className="text-sm font-medium text-gray-500 mb-2 px-2"> </h2> <h2 className="text-sm font-medium text-gray-500 mb-2 px-2"> </h2>
<SettingsOption icon={Lock} label="보안 및 개인정보" description="보안 및 데이터 설정" <SettingsOption icon={Lock} label="보안 및 개인정보" description="보안 및 데이터 설정" onClick={() => navigate('/security-privacy')} />
// 로그인 상태와 관계없이 접근 가능하도록 변경
onClick={() => navigate('/security-privacy')} />
<SettingsOption icon={HelpCircle} label="도움말 및 지원" description="FAQ 및 고객 지원" onClick={() => navigate('/help-support')} /> <SettingsOption icon={HelpCircle} label="도움말 및 지원" description="FAQ 및 고객 지원" onClick={() => navigate('/help-support')} />
</div> </div>
@@ -109,7 +106,8 @@ const Settings = () => {
<div className="mt-10 border-t border-gray-200 pt-4"> <div className="mt-10 border-t border-gray-200 pt-4">
<div className="neuro-flat p-3 rounded-lg"> <div className="neuro-flat p-3 rounded-lg">
<AppVersionInfo showDevInfo={true} /> <h2 className="text-sm font-medium text-gray-500 mb-2 px-2"> </h2>
<AppVersionInfo showDevInfo={true} editable={true} />
</div> </div>
{/* 앱 버전 카드 아래 추가 공간 */} {/* 앱 버전 카드 아래 추가 공간 */}
@@ -120,4 +118,5 @@ const Settings = () => {
<NavBar /> <NavBar />
</div>; </div>;
}; };
export default Settings; export default Settings;