Skip to content

Commit e4a2102

Browse files
committed
feat: add debug logging functionality
1 parent 9902717 commit e4a2102

File tree

3 files changed

+132
-24
lines changed

3 files changed

+132
-24
lines changed

README.md

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -186,33 +186,33 @@ const PlaceDetailsExample = () => {
186186

187187
| Prop | Type | Required | Default | Description |
188188
|------|------|----------|---------|-------------|
189-
| **Essential Props** |
189+
| **Basic Configuration** |
190190
| apiKey | string | Yes | - | Your Google Places API key |
191-
| **Input Configuration** |
192-
| value | string | No | '' | Initial input value |
193-
| placeHolderText | string | No | - | Placeholder text for input |
194-
| minCharsToFetch | number | No | 1 | Minimum characters before fetching |
195-
| debounceDelay | number | No | 200 | Delay before triggering search |
196-
| **Places API Configuration** |
197-
| proxyUrl | string | No | - | Custom proxy URL for Places API requests |
191+
| value | string | No | - | Controlled input value |
192+
| placeHolderText | string | No | - | Placeholder text for the input |
193+
| onPlaceSelect | (place: Place, sessionToken?: string) => void | Yes | - | Callback when a place is selected |
194+
| onTextChange | (text: string) => void | No | - | Callback when input text changes |
195+
| **Search Configuration** |
196+
| proxyUrl | string | No | - | Custom proxy URL for API requests (Required for Expo web) |
198197
| languageCode | string | No | - | Language code (e.g., 'en', 'fr') |
199198
| includedRegionCodes | string[] | No | - | Array of region codes to filter results |
200199
| types | string[] | No | [] | Array of place types to filter |
201200
| biasPrefixText | (text: string) => string | No | - | Optional function to modify the input text before sending to the Places API |
201+
| minCharsToFetch | number | No | 1 | Minimum characters before triggering search |
202+
| debounceDelay | number | No | 200 | Delay in milliseconds before triggering search |
202203
| **Place Details Configuration** |
203204
| fetchDetails | boolean | No | false | Automatically fetch place details when a place is selected |
204205
| detailsProxyUrl | string | No | null | Custom proxy URL for place details requests (Required on Expo web)|
205206
| detailsFields | string[] | No | ['displayName', 'formattedAddress', 'location', 'id'] | Array of fields to include in the place details response. see [Valid Fields](https://developers.google.com/maps/documentation/places/web-service/place-details#fieldmask) |
206207
| **UI Customization** |
207-
| style | StyleProp | No | {} | Custom styles object |
208-
| showLoadingIndicator | boolean | No | true | Show/hide loading indicator |
209-
| showClearButton | boolean | No | true | Show/hide the input clear button |
210-
| forceRTL | boolean | No | undefined | Force RTL layout direction |
211-
hideOnKeyboardDismiss | boolean | No | false | Hide suggestions when keyboard is dismissed
212-
| **Event Handlers** |
213-
| onPlaceSelect | (place: Place \| null, sessionToken?: string) => void | Yes | - | Callback when place is selected |
214-
| onTextChange | (text: string) => void | No | - | Callback triggered on text input changes |
215-
| onError | (error: any) => void | No | - | Callback for handling API errors |
208+
| showLoadingIndicator | boolean | No | true | Show loading spinner during API requests |
209+
| showClearButton | boolean | No | true | Show clear (×) button when input has text |
210+
| forceRTL | boolean | No | - | Force RTL layout (auto-detected if not provided) |
211+
| style | GooglePlacesTextInputStyles | No | {} | Custom styling object |
212+
| hideOnKeyboardDismiss | boolean | No | false | Hide suggestions when keyboard is dismissed |
213+
| **Error Handling & Debugging** |
214+
| onError | (error: any) => void | No | - | Callback when API errors occur |
215+
| enableDebug | boolean | No | false | Enable detailed console logging for troubleshooting |
216216

217217
## Place Details Fetching
218218

src/GooglePlacesTextInput.tsx

Lines changed: 113 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ interface GooglePlacesTextInputProps {
9494
detailsProxyUrl?: string | null; // ✅ Add | null to match JS
9595
detailsFields?: string[];
9696
onError?: (error: any) => void;
97+
enableDebug?: boolean; // ✅ Add debug prop
9798
}
9899

99100
interface GooglePlacesTextInputRef {
@@ -133,6 +134,7 @@ const GooglePlacesTextInput = forwardRef<
133134
detailsProxyUrl = null,
134135
detailsFields = [],
135136
onError,
137+
enableDebug = false,
136138
},
137139
ref
138140
) => {
@@ -209,8 +211,37 @@ const GooglePlacesTextInput = forwardRef<
209211
}
210212
}, [fetchDetails, detailsProxyUrl]);
211213

214+
// Debug logger utility
215+
const debugLog = (category: string, message: string, data?: any) => {
216+
if (enableDebug) {
217+
const timestamp = new Date().toISOString();
218+
console.log(
219+
`[GooglePlacesTextInput:${category}] ${timestamp} - ${message}`
220+
);
221+
if (data) {
222+
console.log(`[GooglePlacesTextInput:${category}] Data:`, data);
223+
}
224+
}
225+
};
226+
212227
const fetchPredictions = async (text: string): Promise<void> => {
228+
debugLog('PREDICTIONS', `Starting fetch for text: "${text}"`);
229+
debugLog('PREDICTIONS', 'Request params', {
230+
text,
231+
apiKey: apiKey ? '[PROVIDED]' : '[MISSING]', // ✅ Security fix
232+
proxyUrl,
233+
sessionToken,
234+
languageCode,
235+
includedRegionCodes,
236+
types,
237+
minCharsToFetch,
238+
});
239+
213240
if (!text || text.length < minCharsToFetch) {
241+
debugLog(
242+
'PREDICTIONS',
243+
`Text too short (${text.length} < ${minCharsToFetch})`
244+
);
214245
setPredictions([]);
215246
return;
216247
}
@@ -230,9 +261,19 @@ const GooglePlacesTextInput = forwardRef<
230261
});
231262

232263
if (error) {
264+
debugLog('PREDICTIONS', 'API Error occurred', {
265+
errorType: error.constructor.name,
266+
errorMessage: error.message,
267+
errorStack: error.stack,
268+
});
233269
onError?.(error);
234270
setPredictions([]);
235271
} else {
272+
debugLog(
273+
'PREDICTIONS',
274+
`Success: ${fetchedPredictions.length} predictions received`
275+
);
276+
debugLog('PREDICTIONS', 'Predictions data', fetchedPredictions);
236277
setPredictions(fetchedPredictions);
237278
setShowSuggestions(fetchedPredictions.length > 0);
238279
}
@@ -243,7 +284,33 @@ const GooglePlacesTextInput = forwardRef<
243284
const fetchPlaceDetails = async (
244285
placeId: string
245286
): Promise<PlaceDetailsFields | null> => {
246-
if (!fetchDetails || !placeId) return null;
287+
debugLog('DETAILS', `Starting details fetch for placeId: ${placeId}`);
288+
debugLog('DETAILS', 'Request params', {
289+
placeId,
290+
apiKey: apiKey ? '[PROVIDED]' : '[MISSING]', // ✅ Security fix
291+
detailsProxyUrl,
292+
sessionToken,
293+
languageCode,
294+
detailsFields,
295+
fetchDetails,
296+
platform: Platform.OS,
297+
});
298+
299+
if (!fetchDetails || !placeId) {
300+
debugLog('DETAILS', 'Skipping details fetch', {
301+
fetchDetails,
302+
placeId,
303+
});
304+
return null;
305+
}
306+
307+
// Web CORS warning
308+
if (Platform.OS === 'web' && !detailsProxyUrl) {
309+
debugLog(
310+
'DETAILS',
311+
'WARNING: Web platform detected without detailsProxyUrl - CORS issues likely'
312+
);
313+
}
247314

248315
setDetailsLoading(true);
249316

@@ -259,10 +326,16 @@ const GooglePlacesTextInput = forwardRef<
259326
setDetailsLoading(false);
260327

261328
if (error) {
329+
debugLog('DETAILS', 'API Error occurred', {
330+
errorType: error.constructor.name,
331+
errorMessage: error.message,
332+
errorStack: error.stack,
333+
});
262334
onError?.(error);
263335
return null;
264336
}
265337

338+
debugLog('DETAILS', 'Success: Details received', details);
266339
return details;
267340
};
268341

@@ -283,17 +356,39 @@ const GooglePlacesTextInput = forwardRef<
283356
suggestion: PredictionItem
284357
): Promise<void> => {
285358
const place = suggestion.placePrediction;
359+
debugLog(
360+
'SELECTION',
361+
`User selected place: ${place.structuredFormat.mainText.text}`
362+
);
363+
debugLog('SELECTION', 'Selected place data', place);
364+
286365
setInputText(place.structuredFormat.mainText.text);
287366
setShowSuggestions(false);
288367
Keyboard.dismiss();
289368

290369
if (fetchDetails) {
370+
debugLog('SELECTION', 'Fetching place details...');
291371
setLoading(true);
292372
const details = await fetchPlaceDetails(place.placeId);
293373
const enrichedPlace: Place = details ? { ...place, details } : place;
374+
375+
debugLog(
376+
'SELECTION',
377+
'Final place object being sent to onPlaceSelect',
378+
{
379+
hasDetails: !!details,
380+
placeKeys: Object.keys(enrichedPlace),
381+
detailsKeys: details ? Object.keys(details) : null,
382+
}
383+
);
384+
294385
onPlaceSelect?.(enrichedPlace, sessionToken);
295386
setLoading(false);
296387
} else {
388+
debugLog(
389+
'SELECTION',
390+
'Sending place without details (fetchDetails=false)'
391+
);
297392
onPlaceSelect?.(place, sessionToken);
298393
}
299394
setSessionToken(generateSessionToken());
@@ -395,17 +490,28 @@ const GooglePlacesTextInput = forwardRef<
395490
return { end: paddingValue };
396491
};
397492

493+
// Debug initialization
494+
useEffect(() => {
495+
if (enableDebug) {
496+
debugLog('INIT', 'Component initialized with props', {
497+
apiKey: apiKey ? '[PROVIDED]' : '[MISSING]', // ✅ Security fix
498+
fetchDetails,
499+
detailsProxyUrl,
500+
detailsFields,
501+
platform: Platform.OS,
502+
minCharsToFetch,
503+
debounceDelay,
504+
});
505+
}
506+
// eslint-disable-next-line react-hooks/exhaustive-deps
507+
}, []); // ✅ Only run on mount
508+
398509
return (
399510
<View style={[styles.container, style.container]}>
400511
<View>
401512
<TextInput
402513
ref={inputRef}
403-
style={[
404-
styles.input,
405-
style.input,
406-
getPadding(),
407-
{ textAlign: isRTL ? 'right' : 'left' },
408-
]}
514+
style={[styles.input, style.input, getPadding(), getTextAlign()]}
409515
placeholder={placeHolderText}
410516
placeholderTextColor={style.placeholder?.color || '#666666'}
411517
value={inputText}

src/services/googlePlacesApi.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,10 @@ export const fetchPlaceDetails = async ({
162162
*/
163163
export const generateUUID = (): string => {
164164
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
165+
/* eslint-disable no-bitwise */
165166
const r = (Math.random() * 16) | 0;
166167
const v = c === 'x' ? r : (r & 0x3) | 0x8;
168+
/* eslint-enable no-bitwise */
167169
return v.toString(16);
168170
});
169171
};

0 commit comments

Comments
 (0)