Skip to content

Commit 0ed2236

Browse files
committed
ras shop finished
1 parent f33565a commit 0ed2236

File tree

9 files changed

+784
-518
lines changed

9 files changed

+784
-518
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# API Integration Update Documentation
2+
3+
## Overview
4+
This document describes the changes made to integrate the JSON API response format into the RAS Member Portal. The API now returns data exclusively in a JSON format that includes membership information, payment history, and available snack items.
5+
6+
## API Response Format
7+
8+
The API now returns data in the following format:
9+
```json
10+
{
11+
"eid": "km54774",
12+
"timestamp": "2025-10-09T17:04:31.788Z",
13+
"payments": [
14+
"id:km54774;shirtM:1",
15+
"rasform25;id:km54774;shirtm:1;shirtl:1",
16+
"rasform25;id:km54774;poptarts:1"
17+
],
18+
"snack": [
19+
{
20+
"id": "chips",
21+
"text": "Chips",
22+
"price": 50,
23+
"online": 0,
24+
"irl": 1
25+
},
26+
{
27+
"id": "caprisun",
28+
"text": "Capri Sun",
29+
"price": 50,
30+
"online": 0,
31+
"irl": 1
32+
}
33+
]
34+
}
35+
```
36+
37+
## Changes Made
38+
39+
### 1. Cleaned up `eidStats.js`:
40+
- Removed all CSV-related code as the API now only returns JSON
41+
- Simplified data processing functions to handle only JSON
42+
- Created functionality to extract payment information from the payments array
43+
- Added handling of snack data from the API
44+
- Updated the member existence check to use the timestamp as an indicator of form completion
45+
46+
### 2. Updated Shop Functionality:
47+
- Modified shop generation to use snack data from the API when available
48+
49+
### 3. Added Diagnostic Tools:
50+
- Created a test module (`testApiIntegration.js`) to verify API integration
51+
- Added a test button to the UI for development purposes
52+
53+
## Technical Details
54+
55+
### JSON Payment Data Handling
56+
The system now parses payment data from an array of strings, where each string may contain multiple items in a semicolon-delimited format. The system extracts item IDs and quantities and aggregates them into a purchases object.
57+
58+
### Snack Data Handling
59+
The API now provides a list of available snack items with details such as price, name, and availability (online/in-person). The shop functionality now incorporates these items when displaying the shop interface.
60+
61+
### Member Existence Check
62+
The timestamp field in the API response is used to determine whether a member has completed the membership form. If the timestamp is present and non-empty, the member is considered to have filled out the form.
63+
64+
## Testing
65+
66+
To test the API integration:
67+
1. Load the member portal page
68+
2. Enter the test EID "km54774"
69+
3. Click the "Run API Integration Tests" button at the bottom of the page
70+
4. Check the browser console for test results
71+
72+
The test verifies:
73+
- Successful data loading
74+
- Member existence check
75+
- Current EID setting
76+
- Availability of snack data
77+
- Availability of purchase history data

public/member/activityLogger.js

Lines changed: 60 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -228,33 +228,34 @@ function generateSubOptions(mainActivity) {
228228
const buttonLabel = document.createElement('label');
229229
buttonLabel.className = 'activity-button';
230230

231-
const checkbox = document.createElement('input');
232-
checkbox.type = 'checkbox';
233-
checkbox.name = mainActivity.toLowerCase();
234-
checkbox.value = subOption.replace(/ /g, ''); // Remove spaces for value
231+
// Change from checkbox to radio button for single select
232+
const radio = document.createElement('input');
233+
radio.type = 'radio'; // Changed from checkbox to radio
234+
radio.name = mainActivity.toLowerCase(); // Same name ensures they belong to the same group
235+
radio.value = subOption.replace(/ /g, ''); // Remove spaces for value
235236

236237
// Check if this sub-option matches the preselected one from URL
237238
if (preSelectedSubOption &&
238239
preSelectedSubOption.toLowerCase() === subOption.replace(/ /g, '').toLowerCase()) {
239-
checkbox.checked = true;
240+
radio.checked = true;
240241
// Will update URL in updateLogButtonState
241242
}
242243

243244
const span = document.createElement('span');
244245
span.textContent = subOption;
245246

246-
buttonLabel.appendChild(checkbox);
247+
buttonLabel.appendChild(radio);
247248
buttonLabel.appendChild(span);
248249
subButtonsContainer.appendChild(buttonLabel);
249250

250-
// Store reference to the checkbox
251+
// Store reference to the radio button
251252
if (!checkboxRefs.sub[mainActivity]) {
252253
checkboxRefs.sub[mainActivity] = [];
253254
}
254-
checkboxRefs.sub[mainActivity].push(checkbox);
255+
checkboxRefs.sub[mainActivity].push(radio);
255256

256257
// Add event listener
257-
checkbox.addEventListener('change', updateLogButtonState);
258+
radio.addEventListener('change', updateLogButtonState);
258259
});
259260

260261
subOptionsContainer.appendChild(subButtonsContainer);
@@ -271,16 +272,16 @@ function updateLogButtonState() {
271272
let selectedSubOption = null;
272273

273274
if (currentlySelectedMainActivity) {
274-
// If activity has sub-options, require at least one sub-option to be selected
275+
// If activity has sub-options, require one sub-option to be selected
275276
if (activityData[currentlySelectedMainActivity].length > 0) {
276277
if (checkboxRefs.sub[currentlySelectedMainActivity]) {
277-
// Check if any sub-options are selected
278+
// Check if any sub-options are selected (now using radio buttons)
278279
const subOptions = checkboxRefs.sub[currentlySelectedMainActivity];
279-
const selectedCheckbox = subOptions.find(checkbox => checkbox.checked);
280+
const selectedRadio = subOptions.find(radio => radio.checked);
280281

281-
if (selectedCheckbox) {
282+
if (selectedRadio) {
282283
shouldEnable = true;
283-
selectedSubOption = selectedCheckbox.value;
284+
selectedSubOption = selectedRadio.value;
284285

285286
// Update URL with activity and suboption
286287
updateUrlWithActivity(currentlySelectedMainActivity, selectedSubOption);
@@ -320,14 +321,17 @@ function setupLogActivityButtonHandler() {
320321
return;
321322
}
322323

324+
// Change button text and disable it during submission
325+
const originalText = this.textContent;
326+
this.textContent = 'Submitting...';
327+
this.disabled = true;
328+
this.classList.add('disabled');
329+
323330
// Prepare data for submission
324331
const activityData = collectActivityData(eid);
325332

326333
// Send data to Google Apps Script
327-
submitActivityData(activityData);
328-
329-
// Reset form state
330-
resetActivityForm();
334+
submitActivityData(activityData, originalText);
331335
});
332336
}
333337

@@ -360,25 +364,25 @@ function collectActivityData(eid) {
360364
if (activityData[mainActivity].length === 0) {
361365
selectedActivities.push(mainActivity);
362366
} else {
363-
// For activities with sub-options
364-
const selectedSubOptions = [];
365-
checkboxRefs.sub[mainActivity].forEach(checkbox => {
366-
if (checkbox.checked) {
367-
// Convert the value back to display text if needed
368-
const optionIndex = activityData[mainActivity].findIndex(
369-
opt => opt.replace(/ /g, '') === checkbox.value
370-
);
371-
if (optionIndex !== -1) {
372-
selectedSubOptions.push(activityData[mainActivity][optionIndex]);
373-
} else {
374-
selectedSubOptions.push(checkbox.value);
375-
}
376-
}
377-
});
367+
// For activities with sub-options (now only one will be selected)
368+
let selectedSubOption = null;
369+
// Find the selected radio button
370+
const selectedRadio = checkboxRefs.sub[mainActivity].find(radio => radio.checked);
378371

379-
if (selectedSubOptions.length > 0) {
380-
selectedActivities.push(`${mainActivity}: ${selectedSubOptions.join(', ')}`);
381-
subActivity = selectedSubOptions.join(', ');
372+
if (selectedRadio) {
373+
// Convert the value back to display text if needed
374+
const optionIndex = activityData[mainActivity].findIndex(
375+
opt => opt.replace(/ /g, '') === selectedRadio.value
376+
);
377+
if (optionIndex !== -1) {
378+
selectedSubOption = activityData[mainActivity][optionIndex];
379+
} else {
380+
selectedSubOption = selectedRadio.value;
381+
}
382+
383+
// Add the activity with its selected sub-option
384+
selectedActivities.push(`${mainActivity}: ${selectedSubOption}`);
385+
subActivity = selectedSubOption;
382386
}
383387
}
384388
}
@@ -396,8 +400,9 @@ function collectActivityData(eid) {
396400
/**
397401
* Submit activity data to Google Apps Script
398402
* @param {Object} activitySubmitData - The data to submit
403+
* @param {string} originalButtonText - The original button text to restore after submission
399404
*/
400-
function submitActivityData(activitySubmitData) {
405+
function submitActivityData(activitySubmitData, originalButtonText) {
401406
postToAppsScript(activitySubmitData,
402407
// Success callback
403408
() => {
@@ -406,19 +411,30 @@ function submitActivityData(activitySubmitData) {
406411

407412
// Log for debugging
408413
console.log('Activity logged:', activitySubmitData);
414+
415+
// Reset form state after successful submission
416+
resetActivityForm(originalButtonText);
409417
},
410418
// Error callback
411419
(error) => {
412420
alert('Error logging activity. Please try again.');
413421
console.error('Error logging activity:', error);
422+
423+
// Restore button state even on error
424+
if (logActivityButton) {
425+
logActivityButton.textContent = originalButtonText;
426+
logActivityButton.disabled = false;
427+
logActivityButton.classList.remove('disabled');
428+
}
414429
}
415430
);
416431
}
417432

418433
/**
419434
* Reset the activity form after submission
435+
* @param {string} [originalButtonText='Log Activity'] - The original button text to restore
420436
*/
421-
function resetActivityForm() {
437+
function resetActivityForm(originalButtonText = 'Log Activity') {
422438
// Reset main activity selection
423439
if (currentlySelectedMainActivity) {
424440
checkboxRefs.main[currentlySelectedMainActivity].checked = false;
@@ -442,7 +458,10 @@ function resetActivityForm() {
442458
const otherInput = document.getElementById('otherActivity');
443459
if (otherInput) otherInput.value = '';
444460

445-
// Disable the button again
446-
logActivityButton.disabled = true;
447-
logActivityButton.classList.add('disabled');
461+
// Restore the button text and disable it
462+
if (logActivityButton) {
463+
logActivityButton.textContent = originalButtonText;
464+
logActivityButton.disabled = true;
465+
logActivityButton.classList.add('disabled');
466+
}
448467
}

0 commit comments

Comments
 (0)