11import { useEffect , useMemo , useState } from 'react'
22import { useMutation , useQuery , useQueryClient } from '@tanstack/react-query'
3- import { Shuffle , Save , Send , Loader2 , AlertCircle } from 'lucide-react'
3+ import { Shuffle , Save , Send , Loader2 , AlertCircle , Download } from 'lucide-react'
44import {
55 getFingerprint ,
66 updateFingerprint ,
99 getDeviceProfiles ,
1010 listCountries ,
1111 randomizeFingerprintWithCountry ,
12+ fetchSamsungFirmware ,
1213} from '../api/client'
1314import type { DeviceFingerprint } from '../types'
1415import clsx from 'clsx'
@@ -31,6 +32,20 @@ function validate(fp: Partial<DeviceFingerprint>): string | null {
3132 return null
3233}
3334
35+ const CSC_CODES = [ 'XEU' , 'BTU' , 'XSP' , 'XEF' , 'KSA' , 'UAE' , 'EGY' , 'XSA' , 'DBT' , 'GEN' ]
36+ const CSC_LABELS : Record < string , string > = {
37+ 'XEU' : 'Europe (Germany)' ,
38+ 'BTU' : 'UK' ,
39+ 'XSP' : 'Spain' ,
40+ 'XEF' : 'France' ,
41+ 'KSA' : 'Saudi Arabia' ,
42+ 'UAE' : 'UAE' ,
43+ 'EGY' : 'Egypt' ,
44+ 'XSA' : 'Australia' ,
45+ 'DBT' : 'Germany (T-Mobile)' ,
46+ 'GEN' : 'Generic/Unlocked' ,
47+ }
48+
3449export default function FingerprintEditor ( { deviceId, isRunning } : Props ) {
3550 const queryClient = useQueryClient ( )
3651 const [ form , setForm ] = useState < Partial < DeviceFingerprint > > ( { } )
@@ -40,6 +55,7 @@ export default function FingerprintEditor({ deviceId, isRunning }: Props) {
4055 const [ selectedCountry , setSelectedCountry ] = useState < string > ( '' )
4156 const [ countrySearch , setCountrySearch ] = useState < string > ( '' )
4257 const [ showCountryDropdown , setShowCountryDropdown ] = useState ( false )
58+ const [ selectedCsc , setSelectedCsc ] = useState < string > ( 'XEU' )
4359
4460 const { data : fp , isLoading } = useQuery ( {
4561 queryKey : [ 'fingerprint' , deviceId ] ,
@@ -77,6 +93,8 @@ export default function FingerprintEditor({ deviceId, isRunning }: Props) {
7793 build_fingerprint : p . build_fingerprint ,
7894 sdk_version : p . sdk_version ,
7995 android_version : p . android_version ,
96+ ap_version : p . ap_version ?? prev . ap_version ,
97+ csc_version : p . csc_version ?? prev . csc_version ,
8098 } ) )
8199 }
82100
@@ -137,6 +155,23 @@ export default function FingerprintEditor({ deviceId, isRunning }: Props) {
137155 } ,
138156 } )
139157
158+ const fetchFirmwareMutation = useMutation ( {
159+ mutationFn : ( ) => fetchSamsungFirmware ( form . device_model || 'SM-G996B' , selectedCsc ) ,
160+ onSuccess : ( data ) => {
161+ setForm ( ( prev ) => ( {
162+ ...prev ,
163+ ap_version : data . ap_version || prev . ap_version ,
164+ csc_version : data . csc_version || prev . csc_version ,
165+ } ) )
166+ setStatusMsg ( `Firmware fetched: AP ${ data . ap_version } , CSC ${ data . csc_version } ` )
167+ setError ( null )
168+ } ,
169+ onError : ( e : Error ) => {
170+ setError ( `Failed to fetch firmware: ${ e . message } ` )
171+ setStatusMsg ( null )
172+ } ,
173+ } )
174+
140175 function set < K extends keyof DeviceFingerprint > ( key : K , value : DeviceFingerprint [ K ] ) {
141176 setForm ( ( prev ) => ( { ...prev , [ key ] : value } ) )
142177 }
@@ -231,6 +266,28 @@ export default function FingerprintEditor({ deviceId, isRunning }: Props) {
231266 >
232267 Randomize + Apply
233268 </ button >
269+ < select
270+ value = { selectedCsc }
271+ onChange = { ( e ) => setSelectedCsc ( e . target . value ) }
272+ className = "input text-sm px-2 py-1"
273+ disabled = { fetchFirmwareMutation . isPending }
274+ >
275+ { CSC_CODES . map ( ( code ) => (
276+ < option key = { code } value = { code } >
277+ { code } - { CSC_LABELS [ code ] }
278+ </ option >
279+ ) ) }
280+ </ select >
281+ < button
282+ type = "button"
283+ className = "btn-secondary btn-sm"
284+ onClick = { ( ) => fetchFirmwareMutation . mutate ( ) }
285+ disabled = { fetchFirmwareMutation . isPending || ! form . device_model }
286+ title = { ! form . device_model ? 'Select a device model first' : undefined }
287+ >
288+ { fetchFirmwareMutation . isPending ? < Loader2 className = "w-4 h-4 animate-spin" /> : < Download className = "w-4 h-4" /> }
289+ Fetch Firmware
290+ </ button >
234291 < button
235292 type = "button"
236293 className = "btn-primary btn-sm"
0 commit comments