Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
aef0dba
Refactor tab layout and enhance navigation experience
jameshaworthcs Mar 14, 2026
375de7b
Enhance tab layout and improve screen responsiveness
jameshaworthcs Mar 14, 2026
e9f384f
Enhance TabScreenScrollView with dynamic background color
jameshaworthcs Mar 14, 2026
6561713
Enhance tab navigation and layout responsiveness
jameshaworthcs Mar 14, 2026
06c79f9
Refactor tab icons in TabLayoutContent for improved consistency
jameshaworthcs Mar 14, 2026
edaeebb
Enhance TabScreenScrollView with native inset handling
jameshaworthcs Mar 14, 2026
6d6dcce
Integrate VersionCheckContext for version management
jameshaworthcs Mar 14, 2026
c3d7098
Refactor TabScreenScrollView for improved iOS handling
jameshaworthcs Mar 14, 2026
5071ae3
Refactor HistoryScreen loading indicator for improved readability
jameshaworthcs Mar 14, 2026
b0bbaaa
Add ReportSheet component for code reporting functionality
jameshaworthcs Mar 14, 2026
e722eb4
Refactor reporting functionality in Checkout components
jameshaworthcs Mar 15, 2026
17cb0b1
Merge origin/main into native-report-button
jameshaworthcs Mar 15, 2026
e6cea92
Remove unused constants from TabScreenScrollView and VersionUpdateBan…
jameshaworthcs Mar 15, 2026
4298746
Update app version to 1.2.7 and remove unused whitespace in VersionUp…
jameshaworthcs Mar 15, 2026
91dfa77
Refactor modal refresh handling in Checkout components
jameshaworthcs Mar 16, 2026
4d880b7
Enhance authentication readiness in ReportSheet and useAuth hook
jameshaworthcs Mar 16, 2026
a3bcacc
Refactor ReportSheet and enhance error handling in useAuth hook
jameshaworthcs Mar 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"expo": {
"name": "CheckOut",
"slug": "CheckOut",
"version": "1.2.6",
"version": "1.2.7",
"orientation": "portrait",
"icon": "./assets/images/icon.png",
"scheme": "checkoutattendance",
Expand Down
56 changes: 47 additions & 9 deletions app/(tabs)/checkout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { UndoBanner } from '@/components/checkout/UndoBanner';
import { Confetti } from '@/components/checkout/Confetti';
import { OptionsSheet } from '@/components/checkout/OptionsSheet';
import { ShareSheet } from '@/components/checkout/ShareSheet';
import { ReportSheet } from '@/components/checkout/ReportSheet';
import { VerificationSheet } from '@/components/checkout/VerificationSheet';
import { AutoSplashModal } from '@/components/checkout/AutoSplashModal';
import { UndoModal } from '@/components/checkout/UndoModal';
Expand Down Expand Up @@ -78,6 +79,9 @@ export default function CheckoutScreen() {
const [selectedCode, setSelectedCode] = useState<Code | null>(null);
const [showSubmitForm, setShowSubmitForm] = useState<string | null>(null);
const [showConfetti, setShowConfetti] = useState(false);
const [reportSheetVisible, setReportSheetVisible] = useState(false);
const [reportSession, setReportSession] = useState<Session | null>(null);
const [reportCode, setReportCode] = useState<Code | null>(null);

// Undo modal state
const [undoModalVisible, setUndoModalVisible] = useState(false);
Expand Down Expand Up @@ -294,7 +298,7 @@ export default function CheckoutScreen() {
setUndoModalSessionId(sessionId);
setUndoModalTk(tk);
setUndoModalVisible(true);
blockRefresh('modal');
blockRefresh('undo-modal');
},
[blockRefresh]
);
Expand All @@ -304,7 +308,7 @@ export default function CheckoutScreen() {
setUndoModalVisible(false);
setUndoModalSessionId(null);
setUndoModalTk(null);
unblockRefresh('modal');
unblockRefresh('undo-modal');
}, [unblockRefresh]);

// Handle undo modal confirm - stays open until complete
Expand All @@ -319,7 +323,7 @@ export default function CheckoutScreen() {
setUndoModalVisible(false);
setUndoModalSessionId(null);
setUndoModalTk(null);
unblockRefresh('modal');
unblockRefresh('undo-modal');

if (!result.success) {
toast.error(result.error || 'Failed to undo submission');
Expand All @@ -340,7 +344,7 @@ export default function CheckoutScreen() {
(session: Session) => {
setSelectedSession(session);
setOptionsSheetVisible(true);
blockRefresh('modal');
blockRefresh('options-modal');
},
[blockRefresh]
);
Expand All @@ -350,7 +354,7 @@ export default function CheckoutScreen() {
(session: Session) => {
setSelectedSession(session);
setShareSheetVisible(true);
blockRefresh('modal');
blockRefresh('share-modal');
},
[blockRefresh]
);
Expand All @@ -360,7 +364,7 @@ export default function CheckoutScreen() {
(code: Code) => {
setSelectedCode(code);
setVerificationSheetVisible(true);
blockRefresh('modal');
blockRefresh('verification-modal');
},
[blockRefresh]
);
Expand All @@ -369,19 +373,40 @@ export default function CheckoutScreen() {
const closeOptions = useCallback(() => {
setOptionsSheetVisible(false);
setSelectedSession(null);
unblockRefresh('modal');
unblockRefresh('options-modal');
}, [unblockRefresh]);

const closeShare = useCallback(() => {
setShareSheetVisible(false);
setSelectedSession(null);
unblockRefresh('modal');
unblockRefresh('share-modal');
}, [unblockRefresh]);

const closeVerification = useCallback(() => {
setVerificationSheetVisible(false);
setSelectedCode(null);
unblockRefresh('modal');
unblockRefresh('verification-modal');
}, [unblockRefresh]);

// Open report sheet
const openReport = useCallback(
(session: Session, code?: Code) => {
const sortedCodes = [...(session.codes || [])].sort((a, b) => b.rejectScore - a.rejectScore);
const targetCode = code || sortedCodes[0];
if (!targetCode) return;
setReportSession(session);
setReportCode(targetCode);
setReportSheetVisible(true);
blockRefresh('report-modal');
},
[blockRefresh]
);

const closeReport = useCallback(() => {
setReportSheetVisible(false);
setReportSession(null);
setReportCode(null);
unblockRefresh('report-modal');
}, [unblockRefresh]);

// Handle input focus/blur
Expand Down Expand Up @@ -610,6 +635,7 @@ export default function CheckoutScreen() {
onOpenOptions={() => openOptions(session)}
onOpenShare={() => openShare(session)}
onOpenVerification={openVerification}
onReportCode={code => openReport(session, code)}
onInputFocus={() => handleInputFocus(session.rejectID)}
onInputBlur={handleInputBlur}
onInputValueChange={handleInputValueChange}
Expand Down Expand Up @@ -657,6 +683,7 @@ export default function CheckoutScreen() {
closeOptions();
openVerification(code);
}}
onReportCode={code => openReport(selectedSession, code)}
/>

<ShareSheet visible={shareSheetVisible} onClose={closeShare} session={selectedSession} />
Expand All @@ -669,6 +696,17 @@ export default function CheckoutScreen() {
code={selectedCode}
/>

{/* Report sheet */}
{reportSession && reportCode && (
<ReportSheet
visible={reportSheetVisible}
onClose={closeReport}
session={reportSession}
codes={[...(reportSession.codes || [])].sort((a, b) => b.rejectScore - a.rejectScore)}
initialCode={reportCode}
/>
)}

{/* AutoSplash modal */}
<AutoSplashModal
visible={showAutoSplash}
Expand Down
3 changes: 2 additions & 1 deletion components/TabScreenScrollView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const TabScreenScrollView = forwardRef<TabScreenScrollViewRef, TabScreenS
// Only add top padding for native tabs where TopBar is absolute-positioned.
// In Expo Go, TopBar is a flex sibling so no extra padding is needed.
const topInset = isExpoGo ? 0 : insets.top + TOP_BAR_HEIGHT;
const isNativeIOS = !isExpoGo && Platform.OS === 'ios';
const { connectionState } = useConnectionContext();
const { isOutdated, isForcedUpdate } = useVersionCheckContext();
const backgroundColor = useThemeColor({}, 'background');
Expand Down Expand Up @@ -83,7 +84,7 @@ export const TabScreenScrollView = forwardRef<TabScreenScrollViewRef, TabScreenS
{...props}
style={[{ backgroundColor }, props.style]}
keyboardShouldPersistTaps="handled"
contentInsetAdjustmentBehavior="never"
contentInsetAdjustmentBehavior={isNativeIOS ? 'scrollableAxes' : 'never'}
automaticallyAdjustContentInsets={false}
scrollIndicatorInsets={{ top: topInset, bottom: totalBottomPadding }}
contentContainerStyle={[
Expand Down
26 changes: 9 additions & 17 deletions components/checkout/OptionsSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { View, TouchableOpacity, StyleSheet } from 'react-native';
import { router } from 'expo-router';
import { ThemedText } from '@/components/ThemedText';
import { useAppTheme } from '@/hooks/useAppTheme';
import { getApiUrl } from '@/constants/api';
import { openAuthenticatedUrl } from '@/utils/api';
import { BottomSheet } from './BottomSheet';
import type { Session, Code } from '@/types/liveClasses';

Expand All @@ -14,6 +12,7 @@ interface OptionsSheetProps {
session: Session;
onSubmitDifferentCode: () => void;
onViewVerification?: (code: Code) => void;
onReportCode?: (code: Code) => void;
}

export function OptionsSheet({
Expand All @@ -22,27 +21,17 @@ export function OptionsSheet({
session,
onSubmitDifferentCode,
onViewVerification,
onReportCode,
}: OptionsSheetProps) {
const { theme, isDark } = useAppTheme();
const [showMoreInfo, setShowMoreInfo] = React.useState(false);

const handleReportCode = async () => {
const primaryCode = session.codes?.[0];
if (primaryCode) {
const codeId = primaryCode.codeIDs?.[0] || '';
const path = `/support?pre=report-code&chc=${primaryCode.checkinCode}&codeID=${codeId}`;
const apiUrl = await getApiUrl();
openAuthenticatedUrl(path, `${apiUrl}${path}`);
}
onClose();
};

const handleOpenSettings = () => {
onClose();
router.push('/settings');
};

const primaryCode = session.codes?.[0];
const primaryCode = [...(session.codes || [])].sort((a, b) => b.rejectScore - a.rejectScore)[0];

return (
<BottomSheet visible={visible} onClose={onClose}>
Expand Down Expand Up @@ -87,15 +76,18 @@ export function OptionsSheet({
)}

{/* Report incorrect code */}
{primaryCode && (
{primaryCode && onReportCode && (
<TouchableOpacity
style={[
styles.option,
{ backgroundColor: isDark ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.05)' },
]}
onPress={handleReportCode}>
onPress={() => {
onReportCode?.(primaryCode);
onClose();
}}>
<ThemedText style={styles.optionText}>Report incorrect code</ThemedText>
<ThemedText style={[styles.optionArrow, { color: theme.secondary }]}></ThemedText>
<ThemedText style={[styles.optionArrow, { color: theme.secondary }]}></ThemedText>
</TouchableOpacity>
)}

Expand Down
Loading
Loading