Skip to content

Commit

Permalink
Merge pull request #203 from ryanmio/Release_v0.6.1
Browse files Browse the repository at this point in the history
Release v0.6.1
  • Loading branch information
ryanmio authored Aug 26, 2023
2 parents 169bb70 + 93e0f7f commit 90f84d9
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 50 deletions.
53 changes: 33 additions & 20 deletions src/components/GrowerStatsProfile/GrowerSearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import getGrowerSuggestions from '../../utilities/getGrowerSuggestions';
import fetchPumpkins from '../../utilities/fetchPumpkins';
import { toast } from 'react-hot-toast';
import TableSection from './TableSection';
import { trackUserEvent, trackError, GA_ACTIONS, GA_CATEGORIES } from '../../utilities/error-analytics';


// Function to convert a string to title case
function toTitleCase(str) {
Expand Down Expand Up @@ -39,34 +41,45 @@ const GrowerSearch = ({ user, handleSave }) => {
const [state, dispatch] = useReducer(reducer, initialState);

useEffect(() => {
if (state.growerName) {
getGrowerSuggestions(toTitleCase(state.growerName), (error, suggestions) => {
if (error) {
toast.error('Error fetching grower suggestions: ' + error.message);
} else {
dispatch({ type: 'SET_SUGGESTIONS', payload: suggestions });
}
});
}
}, [state.growerName]);
if (state.growerName) {
// Track the search initiation event
trackUserEvent(GA_ACTIONS.Search_Initiated, GA_CATEGORIES.GrowerSearch);

getGrowerSuggestions(toTitleCase(state.growerName), (error, suggestions) => {
if (error) {
// Track the error event
trackError(error.message, 'getGrowerSuggestions', GA_CATEGORIES.GrowerSearch, GA_ACTIONS.Fetch_Suggestions_Failure);
toast.error('Error fetching grower suggestions: ' + error.message);
} else {
// Track the successful fetch event
trackUserEvent(GA_ACTIONS.Fetch_Suggestions_Success, GA_CATEGORIES.GrowerSearch);
dispatch({ type: 'SET_SUGGESTIONS', payload: suggestions });
}
});
}
}, [state.growerName]);

useEffect(() => {
if (state.selectedGrower && state.selectedGrower.id) {
fetchPumpkins(state.selectedGrower.id)
.then((pumpkins) => {
dispatch({ type: 'SET_PUMPKIN_PREVIEW', payload: pumpkins });
})
.catch((error) => {
toast.error('Error fetching pumpkins: ' + error.message);
});
}
}, [state.selectedGrower]);
if (state.selectedGrower && state.selectedGrower.id) {
fetchPumpkins(state.selectedGrower.id)
.then((pumpkins) => {
trackUserEvent(GA_ACTIONS.Pumpkin_Data_Fetched, GA_CATEGORIES.GrowerSearch);
dispatch({ type: 'SET_PUMPKIN_PREVIEW', payload: pumpkins });
})
.catch((error) => {
trackError(error, 'fetchPumpkins', GA_CATEGORIES.GrowerSearch, GA_ACTIONS.Pumpkin_Data_Error);
});
}
}, [state.selectedGrower]);


const handleSelectGrower = (grower) => {
trackUserEvent(GA_ACTIONS.Grower_Selected, GA_CATEGORIES.GrowerSearch);
dispatch({ type: 'SET_SELECTED_GROWER', payload: grower });
};

const handleConfirm = () => {
trackUserEvent(GA_ACTIONS.Grower_Confirmed, GA_CATEGORIES.GrowerSearch);
console.log('handleConfirm called. user.uid:', user.uid, 'state.selectedGrower.id:', state.selectedGrower.id);
console.log('handleConfirm', user.uid, state.selectedGrower.id);
handleSave(state.selectedGrower.id); // Call handleSave from MyStats
Expand Down
27 changes: 16 additions & 11 deletions src/components/GrowerStatsProfile/MyStats.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Spinner from '../Spinner';
import useGrowerData from '../../utilities/useGrowerDataHook';
import { toast } from 'react-hot-toast';
import { Link } from 'react-router-dom';
import { trackUserEvent, trackError, GA_ACTIONS, GA_CATEGORIES } from '../../utilities/error-analytics';

const MyStats = () => {
const { user, growerId, setGrowerId } = useContext(UserContext);
Expand All @@ -18,20 +19,24 @@ const MyStats = () => {

const handleEdit = () => {
setEditingGrowerId(true);
trackUserEvent(GA_ACTIONS.EDIT_GROWER_ID, GA_CATEGORIES.MY_STATS);
};

const handleSave = (newGrowerId) => {
updateDoc(doc(db, 'Users', user.uid), {
growerId: newGrowerId
}).then(() => {
setGrowerId(newGrowerId); // Update growerId in context
setEditingGrowerId(false); // Exit editing mode
toast.success('Grower ID confirmed!'); // Add this line to show a success toast
}).catch(error => {
console.error('Error updating document:', error); // Keep this log to record potential errors
toast.error('Error confirming Grower ID.'); // Add this line to show an error toast
});
};
updateDoc(doc(db, 'Users', user.uid), {
growerId: newGrowerId
}).then(() => {
setGrowerId(newGrowerId); // Update growerId in context
setEditingGrowerId(false); // Exit editing mode
toast.success('Grower ID confirmed!'); // Show a success toast
trackUserEvent(GA_ACTIONS.CONFIRM_GROWER_ID, GA_CATEGORIES.MY_STATS); // Track successful update
}).catch(error => {
console.error('Error updating document:', error); // Keep this log to record potential errors
toast.error('Error confirming Grower ID.'); // Show an error toast
trackError(error.message, GA_CATEGORIES.MY_STATS, 'MyStats', GA_ACTIONS.CONFIRM_GROWER_ID); // Track error
});
};


if (loading) {
return <Spinner />;
Expand Down
19 changes: 16 additions & 3 deletions src/components/GrowerStatsProfile/Search.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import algoliasearch from 'algoliasearch/lite';
import { InstantSearch, SearchBox, Hits } from 'react-instantsearch';
import { useNavigate, useLocation } from 'react-router-dom';
import { GrowerContext } from '../../contexts/GrowerContext';
import { trackUserEvent, trackError, GA_ACTIONS, GA_CATEGORIES } from '../../utilities/error-analytics';


const searchClient = algoliasearch('SPV52PLJT9', process.env.REACT_APP_ALGOLIA_API_KEY);

Expand All @@ -12,7 +14,9 @@ const Hit = ({ hit }) => {
const location = useLocation(); // Import useLocation

const handleHitClick = () => {
trackUserEvent(GA_ACTIONS.SEARCH_CLICK, GA_CATEGORIES.SEARCH);
const collectionType = hit.path.split('/')[0];


switch (collectionType) {
case 'Stats_Growers':
Expand All @@ -28,8 +32,10 @@ const Hit = ({ hit }) => {
navigate(`/site-profile/${encodeURIComponent(hit.objectID)}`);
break;
default:
console.error('Unknown collection type:', collectionType);
break;
const errorMsg = 'Unknown collection type: ' + collectionType;
console.error(errorMsg);
trackError(errorMsg, GA_CATEGORIES.SEARCH, 'Search', GA_ACTIONS.SEARCH_CLICK);
break;
}
};

Expand Down Expand Up @@ -58,7 +64,9 @@ const Hit = ({ hit }) => {
</>
);
default:
console.error('Unknown collection type:', collectionType);
const errorMsg = 'Unknown collection type: ' + collectionType;
console.error(errorMsg);
trackError(errorMsg, GA_CATEGORIES.SEARCH, 'Search', GA_ACTIONS.SEARCH_CLICK);
break;
}
};
Expand All @@ -75,11 +83,16 @@ const Hit = ({ hit }) => {
const NoIcon = () => null;

const Search = () => {
const handleSearch = (event) => {
trackUserEvent(GA_ACTIONS.PERFORM_SEARCH, GA_CATEGORIES.SEARCH);
};

return (
<div className="bg-f2eee3 text-36382e">
<InstantSearch searchClient={searchClient} indexName="AllTypes">
<div className="p-4 flex items-center">
<SearchBox
onSearchChange={handleSearch}
placeholder="Search for growers, pumpkins, or sites..."
className="w-full rounded-md border border-gray-300 text-xl"
submitIconComponent={NoIcon}
Expand Down
24 changes: 16 additions & 8 deletions src/components/ImageCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Button from '../utilities/Button';
import Spinner from '../components/Spinner';
import { deleteObject } from 'firebase/storage';
import { differenceInDays } from 'date-fns';
import { trackUserEvent, trackError, GA_ACTIONS, GA_CATEGORIES } from '../utilities/error-analytics';

const ImageCard = ({ pumpkinId, pumpkinName }) => {
const [images, setImages] = useState([]);
Expand Down Expand Up @@ -110,14 +111,17 @@ const calculateDaysAfterPollination = async (pumpkinId, shareDate) => {

// Open the Facebook share dialog
FB.ui(shareContent, function(response) {
if (response && !response.error_message) {
toast.success('Image shared successfully.');
} else {
toast.error('Failed to share image. Please try again.');
}
});
if (response && !response.error_message) {
trackUserEvent(GA_ACTIONS.Share_Success, GA_CATEGORIES.ImageCard);
toast.success('Image shared successfully.');
} else {
trackError('Failed to share image', GA_CATEGORIES.ImageCard, 'handleShare', GA_ACTIONS.Share_Failure);
toast.error('Failed to share image. Please try again.');
}
});
} catch (e) {
// If there's an error, dismiss the loading toast and show an error toast
trackError('Failed to create sharable link', GA_CATEGORIES.ImageCard, 'handleShare', GA_ACTIONS.Share_Failure);
toast.dismiss(toastId);
toast.error('Failed to create sharable link. Please try again.');
}
Expand Down Expand Up @@ -160,7 +164,9 @@ const calculateDaysAfterPollination = async (pumpkinId, shareDate) => {

// Revoke the blob URL to free up resources
URL.revokeObjectURL(blobURL);
} catch (error) {
trackUserEvent(GA_ACTIONS.Download_Success, GA_CATEGORIES.ImageCard);
} catch (error) {
trackError('Failed to download image', GA_CATEGORIES.ImageCard, 'handleDownload', GA_ACTIONS.Download_Failure);
console.error('Error downloading image:', error);
toast.error('Failed to download image. Please try again.');
}
Expand Down Expand Up @@ -194,7 +200,9 @@ const calculateDaysAfterPollination = async (pumpkinId, shareDate) => {

// Show a success toast
toast.success('Image deleted successfully.');
} catch (error) {
trackUserEvent(GA_ACTIONS.Delete_Success, GA_CATEGORIES.ImageCard);
} catch (error) {
trackError('Failed to delete image', GA_CATEGORIES.ImageCard, 'handleDelete', GA_ACTIONS.Delete_Failure);
console.error('Error deleting image:', error);
toast.error('Failed to delete image. Please try again.');
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
# Implementation Guide: Adding Google Analytics 4 (GA4) to New Components in PumpkinPal

## Step 0: Update GA Actions and Categories (Preparation)
## Step 0: Update GA ACTIONS and CATEGORIES (Preparation)

Before implementing GA in a new component, update the `GA_Actions` and `GA_Categories` in `error-analytics.js` to include new actions or categories specific to the component.
Before implementing GA in a new component, update the `GA_ACTIONS` and `GA_CATEGORIES` in `error-analytics.js` to include new actions or categories specific to the component.

```javascript
// In error-analytics.js
export const GA_Actions = {
export const GA_ACTIONS = {
// ...existing actions
NEW_ACTION: 'new_action',
};

export const GA_Categories = {
export const GA_CATEGORIES = {
// ...existing categories
NEW_CATEGORY: 'New Category',
};
```
## Step 1: Import the Utility Functions and Constants
Import the utility functions trackUserEvent and trackError, as well as GA_Actions and GA_Categories, into the component where you want to add GA4 tracking.
Import the utility functions trackUserEvent and trackError, as well as GA_ACTIONS and GA_CATEGORIES, into the component where you want to add GA4 tracking.

```javascript
import { trackUserEvent, trackError, GA_Actions, GA_Categories } from '../utilities/error-analytics';
import { trackUserEvent, trackError, GA_ACTIONS, GA_CATEGORIES } from '../utilities/error-analytics';
```
## Step 2: Identify User Events to Track
Determine which user events in the component you want to track.
Expand All @@ -31,7 +31,7 @@ Use the trackUserEvent function and the imported constants to track the identifi
```javascript
const handleButtonClick = () => {
// Your code here
trackUserEvent(GA_Actions.NEW_ACTION, GA_Categories.NEW_CATEGORY);
trackUserEvent(GA_ACTIONS.NEW_ACTION, GA_CATEGORIES.NEW_CATEGORY);
};
```
## Step 4: Identify Errors to Track
Expand All @@ -45,7 +45,7 @@ const fetchData = async () => {
try {
// Your code here
} catch (error) {
trackError(error.message, GA_Categories.NEW_CATEGORY, 'ComponentName', GA_Actions.NEW_ACTION);
trackError(error.message, GA_CATEGORIES.NEW_CATEGORY, 'ComponentName', GA_ACTIONS.NEW_ACTION);
}
};
```
Expand Down
24 changes: 24 additions & 0 deletions src/utilities/error-analytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import ReactGA from 'react-ga4';
export const GA_CATEGORIES = {
USER: "User",
SYSTEM: "System",
MY_STATS: 'My Stats',
SEARCH: 'Search',
IMAGE_CARD: 'ImageCard',
GrowerSearch: 'GrowerSearch',
};

export const GA_ACTIONS = {
Expand All @@ -19,6 +23,24 @@ export const GA_ACTIONS = {
DELETE_ACCOUNT: "Delete Account",
UPDATE_PREFERENCES: "Update Preferences",
EXPORT_DATA: "Export Data",
EDIT_GROWER_ID: 'edit_grower_id',
CONFIRM_GROWER_ID: 'confirm_grower_id',
NAVIGATE_PUMPKIN_DETAILS: 'navigate_pumpkin_details',
PERFORM_SEARCH: 'perform_search',
SEARCH_CLICK: 'search_click',
DOWNLOAD_SUCCESS: 'Download_Success',
DOWNLOAD_FAILURE: 'Download_Failure',
SHARE_SUCCESS: 'Share_Success',
SHARE_FAILURE: 'Share_Failure',
DELETE_SUCCESS: 'Delete_Success',
DELETE_FAILURE: 'Delete_Failure',
Search_Initiated: 'Search_Initiated',
Fetch_Suggestions_Success: 'Fetch_Suggestions_Success',
Fetch_Suggestions_Failure: 'Fetch_Suggestions_Failure',
Pumpkin_Data_Fetched: 'Pumpkin_Data_Fetched',
Pumpkin_Data_Error: 'Pumpkin_Data_Error',
Grower_Selected: 'Grower_Selected',
Grower_Confirmed: 'Grower_Confirmed',
};


Expand All @@ -28,6 +50,8 @@ export function trackError(error, method, category = GA_CATEGORIES.SYSTEM, actio
category: category,
action: action,
label: `${method} - ${error.code || "Unknown error"}: ${error.message || ""}`,
dimensions: {
'dimension1': process.env.NODE_ENV // 'development' or 'production'
});
}

Expand Down

0 comments on commit 90f84d9

Please sign in to comment.