fix build issue in main and properly added library tab#4
Conversation
…fixed | feat(library): properly added initial version
📝 WalkthroughWalkthroughThis PR introduces a new Library Rooms reservation tab screen enabling users to draft group reservations with date, time, duration, occupancy, floor preference, and toggles for accessibility features. Validation enforces group sizes of 2–9 and requires policy acknowledgment before submission; on submit, the app opens the official CPP reservation URL and tracks status across draft, sent, and done states. A new dependency is added and minor whitespace changes are made. ChangesLibrary Rooms Reservation Implementation
🎯 2 (Simple) | ⏱️ ~12 minutes
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/`(tabs)/library.tsx:
- Around line 41-47: getDays currently uses d.toISOString().slice(0,10) which
produces UTC dates and can shift the day for users near midnight; change getDays
to generate local YYYY-MM-DD keys instead (e.g. compute year/month/day from the
Date object's getFullYear(), getMonth(), getDate() or use
toLocaleDateString('en-CA')) so the returned value reflects the user's local
date; also create a base Date once (e.g. const base = new Date()) and for each
iteration clone/adjust it (base.getDate() + i) to avoid mutating a single Date
across iterations.
- Around line 75-94: In continueToOfficialBooking(), don’t call
setStatus("sent") before verifying the external URL; instead use
Linking.canOpenURL(CPP_RESERVE_URL) and attempt Linking.openURL inside a
try/catch (or use the promise rejection handler), only call setStatus("sent")
after openURL succeeds, and show an Alert if canOpenURL/openURL fails so errors
are handled and status remains accurate; apply the same change to the other
openURL usage in this file.
- Around line 97-341: The file uses inline style objects for layout and spacing;
refactor layout props (flex, flexDirection, padding, gap, margin, alignItems,
justifyContent, flexWrap, etc.) into NativeWind className strings while keeping
dynamic colors and fontFamily in style. For the main screen, update
SafeAreaView, ScrollView, the heading Texts, the container Views (the
reservation draft box and form rows), Horizontal, and all Pressable buttons
(including the policy toggle, submit Pressable and direct LibCal link) to use
className for spacing/layout and preserve color/fontFamily in their style props;
do the same for helper components referenced later (Chip, Toggle, Summary,
Label) so only layout moves to className and color/fontFamily remain in style.
Ensure className values reflect the existing layout (e.g., padding, margin,
flex, gap, flex-row, flex-wrap, items-center, justify-center) and remove those
layout properties from style objects.
In `@package.json`:
- Line 40: package.json now lists the new dependency
react-native-is-edge-to-edge@^1.3.1 but the backend/package-lock.json was not
updated; run npm install in the backend to regenerate the lockfile so the new
dependency is resolved and committed, then verify package-lock.json reflects
react-native-is-edge-to-edge and include the updated lockfile in the PR before
merging.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 3801365a-28a8-47ca-b30e-c01030568758
⛔ Files ignored due to path filters (2)
Archive.zipis excluded by!**/*.zippackage-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (4)
app/(tabs)/_layout.tsxapp/(tabs)/library.tsxapp/(tabs)/map.tsxpackage.json
| function getDays() { | ||
| return Array.from({ length: 7 }, (_, i) => { | ||
| const d = new Date(); | ||
| d.setDate(d.getDate() + i); | ||
| return { | ||
| value: d.toISOString().slice(0, 10), | ||
| label: |
There was a problem hiding this comment.
Use local date keys instead of UTC ISO strings
toISOString().slice(0, 10) can shift the date for users near midnight due to UTC conversion, producing wrong day values in the draft.
Proposed fix
function getDays() {
return Array.from({ length: 7 }, (_, i) => {
const d = new Date();
d.setDate(d.getDate() + i);
+ const localDate = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
return {
- value: d.toISOString().slice(0, 10),
+ value: localDate,
label:
i === 0
? "Today"
: d.toLocaleDateString("en-US", {
weekday: "short",
month: "short",
day: "numeric",
}),
};
});
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/`(tabs)/library.tsx around lines 41 - 47, getDays currently uses
d.toISOString().slice(0,10) which produces UTC dates and can shift the day for
users near midnight; change getDays to generate local YYYY-MM-DD keys instead
(e.g. compute year/month/day from the Date object's getFullYear(), getMonth(),
getDate() or use toLocaleDateString('en-CA')) so the returned value reflects the
user's local date; also create a base Date once (e.g. const base = new Date())
and for each iteration clone/adjust it (base.getDate() + i) to avoid mutating a
single Date across iterations.
| async function continueToOfficialBooking() { | ||
| if (!validGroup) { | ||
| Alert.alert( | ||
| "Invalid group size", | ||
| "CPP group study rooms require 2 to 9 students." | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| if (!policy) { | ||
| Alert.alert( | ||
| "Policy confirmation required", | ||
| "Confirm that you understand CPP Library policies before continuing." | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| setStatus("sent"); | ||
| await Linking.openURL(CPP_RESERVE_URL); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's find and read the library.tsx file
find . -name "library.tsx" -path "*/app/tabs/*" | head -5Repository: lebuckman/broncopath
Length of output: 46
🏁 Script executed:
# Get line count to understand file size
wc -l app/\(tabs\)/library.tsx 2>/dev/null || find . -path "*app*(tabs)*library.tsx" -type fRepository: lebuckman/broncopath
Length of output: 91
🏁 Script executed:
# Use a more direct approach to find the file
fd -t f "library.tsx" appRepository: lebuckman/broncopath
Length of output: 87
🏁 Script executed:
# Read lines 75-94 to see the continueToOfficialBooking function
sed -n '75,94p' app/\(tabs\)/library.tsxRepository: lebuckman/broncopath
Length of output: 527
🏁 Script executed:
# Read context around line 327
sed -n '320,335p' app/\(tabs\)/library.tsxRepository: lebuckman/broncopath
Length of output: 480
🏁 Script executed:
# Search for all Linking.openURL usages
rg "Linking\.openURL" app/\(tabs\)/library.tsx -n -A 2 -B 2Repository: lebuckman/broncopath
Length of output: 322
🏁 Script executed:
# Check if Linking.canOpenURL is used anywhere in the codebase
rg "canOpenURL" --type ts --type tsxRepository: lebuckman/broncopath
Length of output: 92
🏁 Script executed:
# Search for Linking imports to understand usage pattern
rg "Linking\." app/\(tabs\)/library.tsx -B 3 -A 3 | head -30Repository: lebuckman/broncopath
Length of output: 331
🏁 Script executed:
# Check entire imports section to see Linking import
head -20 app/\(tabs\)/library.tsxRepository: lebuckman/broncopath
Length of output: 607
Handle URL-launch failures before advancing reservation status
setStatus("sent") runs before verifying the external URL can be opened, and both Linking.openURL(...) calls are unguarded. If launch fails, status becomes inaccurate and errors can bubble unhandled.
Proposed fix
async function continueToOfficialBooking() {
if (!validGroup) {
@@
if (!policy) {
@@
}
-
- setStatus("sent");
- await Linking.openURL(CPP_RESERVE_URL);
+ try {
+ const supported = await Linking.canOpenURL(CPP_RESERVE_URL);
+ if (!supported) {
+ Alert.alert("Unable to open link", "Please open the CPP reservation page in your browser.");
+ return;
+ }
+ await Linking.openURL(CPP_RESERVE_URL);
+ setStatus("sent");
+ } catch {
+ Alert.alert("Unable to open link", "Please try again in a moment.");
+ }
}
@@
-<Pressable
- onPress={() => Linking.openURL(LIBCAL_DIRECT_URL)}
+<Pressable
+ onPress={async () => {
+ try {
+ const supported = await Linking.canOpenURL(LIBCAL_DIRECT_URL);
+ if (!supported) {
+ Alert.alert("Unable to open link", "Please open LibCal directly in your browser.");
+ return;
+ }
+ await Linking.openURL(LIBCAL_DIRECT_URL);
+ } catch {
+ Alert.alert("Unable to open link", "Please try again in a moment.");
+ }
+ }}Also applies to: 327
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/`(tabs)/library.tsx around lines 75 - 94, In continueToOfficialBooking(),
don’t call setStatus("sent") before verifying the external URL; instead use
Linking.canOpenURL(CPP_RESERVE_URL) and attempt Linking.openURL inside a
try/catch (or use the promise rejection handler), only call setStatus("sent")
after openURL succeeds, and show an Alert if canOpenURL/openURL fails so errors
are handled and status remains accurate; apply the same change to the other
openURL usage in this file.
There was a problem hiding this comment.
@lebuckman Sure! Here's a quick recap of the two spots to address:
-
continueToOfficialBooking()(Lines 90–91) —setStatus("sent")is called before the URL open is confirmed. IfLinking.openURLrejects, the status will incorrectly read"sent". The fix is to:- Use
Linking.canOpenURL()first to check support. - Wrap
Linking.openURL()in atry/catch. - Only call
setStatus("sent")afteropenURLresolves successfully.
- Use
-
The LibCal direct link (Line 327) — The bare
Linking.openURL(LIBCAL_DIRECT_URL)call also needs the samecanOpenURLcheck +try/catchwrapper with a user-facingAlerton failure.
The proposed diff in the review comment above covers both cases — feel free to use it as a starting point!
| <SafeAreaView edges={["top"]} style={{ flex: 1, backgroundColor: Colors.bg }}> | ||
| <ScrollView contentContainerStyle={{ padding: 20, paddingBottom: 44 }}> | ||
| <Text | ||
| style={{ | ||
| color: Colors.text, | ||
| fontFamily: Fonts.display, | ||
| fontSize: 28, | ||
| }} | ||
| > | ||
| Library Rooms | ||
| </Text> | ||
|
|
||
| <Text | ||
| style={{ | ||
| color: Colors.muted, | ||
| fontFamily: Fonts.body, | ||
| fontSize: 12, | ||
| marginTop: 4, | ||
| marginBottom: 18, | ||
| }} | ||
| > | ||
| Build your reservation, then finish through CPP SSO. | ||
| </Text> | ||
|
|
||
| <InfoCard status={status} /> | ||
|
|
||
| <Label icon="calendar">Date</Label> | ||
| <Horizontal> | ||
| {days.map((d) => ( | ||
| <Chip | ||
| key={d.value} | ||
| label={d.label} | ||
| selected={date === d.value} | ||
| onPress={() => setDate(d.value)} | ||
| /> | ||
| ))} | ||
| </Horizontal> | ||
|
|
||
| <Label icon="clock">Start time</Label> | ||
| <Horizontal> | ||
| {TIMES.map((t) => ( | ||
| <Chip | ||
| key={t} | ||
| label={t} | ||
| selected={time === t} | ||
| onPress={() => setTime(t)} | ||
| /> | ||
| ))} | ||
| </Horizontal> | ||
|
|
||
| <Label icon="watch">Duration</Label> | ||
| <View style={{ flexDirection: "row", flexWrap: "wrap", gap: 8 }}> | ||
| {DURATIONS.map((d) => ( | ||
| <Chip | ||
| key={d.value} | ||
| label={d.label} | ||
| selected={duration === d.value} | ||
| onPress={() => setDuration(d.value)} | ||
| /> | ||
| ))} | ||
| </View> | ||
|
|
||
| <Label icon="users">Group size</Label> | ||
| <TextInput | ||
| value={groupSize} | ||
| onChangeText={setGroupSize} | ||
| keyboardType="number-pad" | ||
| placeholder="2-9" | ||
| placeholderTextColor={Colors.muted} | ||
| style={{ | ||
| backgroundColor: Colors.card, | ||
| borderColor: validGroup ? Colors.border : Colors.highBorder, | ||
| borderWidth: 1, | ||
| borderRadius: 14, | ||
| color: Colors.text, | ||
| fontFamily: Fonts.body, | ||
| padding: 14, | ||
| marginBottom: 6, | ||
| }} | ||
| /> | ||
|
|
||
| <Label icon="layers">Preferred floor</Label> | ||
| <View style={{ flexDirection: "row", flexWrap: "wrap", gap: 8 }}> | ||
| {FLOORS.map((f) => ( | ||
| <Chip | ||
| key={f} | ||
| label={f === "Any" ? "Any floor" : `Floor ${f}`} | ||
| selected={floor === f} | ||
| onPress={() => setFloor(f)} | ||
| /> | ||
| ))} | ||
| </View> | ||
|
|
||
| <Label icon="sliders">Preferences</Label> | ||
| <Toggle | ||
| label="Power outlet preferred" | ||
| value={power} | ||
| onPress={() => setPower(!power)} | ||
| /> | ||
| <Toggle | ||
| label="ADA-accessible room preferred" | ||
| value={ada} | ||
| onPress={() => setAda(!ada)} | ||
| /> | ||
|
|
||
| <View | ||
| style={{ | ||
| backgroundColor: Colors.surface, | ||
| borderColor: Colors.border, | ||
| borderWidth: 1, | ||
| borderRadius: 18, | ||
| padding: 16, | ||
| marginTop: 16, | ||
| }} | ||
| > | ||
| <Text | ||
| style={{ | ||
| color: Colors.text, | ||
| fontFamily: Fonts.bodySemiBold, | ||
| fontSize: 14, | ||
| marginBottom: 10, | ||
| }} | ||
| > | ||
| Reservation draft | ||
| </Text> | ||
|
|
||
| <Summary label="Date" value={date} /> | ||
| <Summary label="Time" value={time} /> | ||
| <Summary label="Duration" value={`${duration} minutes`} /> | ||
| <Summary label="Group" value={`${groupSize} students`} /> | ||
| <Summary | ||
| label="Needs" | ||
| value={[ | ||
| floor === "Any" ? "Any floor" : `Floor ${floor}`, | ||
| power ? "Power outlet" : null, | ||
| ada ? "ADA" : null, | ||
| ] | ||
| .filter(Boolean) | ||
| .join(" · ")} | ||
| /> | ||
| </View> | ||
|
|
||
| <Pressable | ||
| onPress={() => setPolicy(!policy)} | ||
| style={{ | ||
| backgroundColor: policy ? Colors.accentBg : Colors.card, | ||
| borderColor: policy ? Colors.accentBorder : Colors.border, | ||
| borderWidth: 1, | ||
| borderRadius: 18, | ||
| padding: 16, | ||
| marginTop: 14, | ||
| flexDirection: "row", | ||
| gap: 12, | ||
| }} | ||
| > | ||
| <Feather | ||
| name={policy ? "check-square" : "square"} | ||
| size={22} | ||
| color={policy ? Colors.accent : Colors.muted} | ||
| /> | ||
| <Text | ||
| style={{ | ||
| color: Colors.text, | ||
| fontFamily: Fonts.body, | ||
| fontSize: 12, | ||
| lineHeight: 18, | ||
| flex: 1, | ||
| }} | ||
| > | ||
| I understand final booking must be completed through CPP Library, | ||
| including policy agreement and CPP SSO. | ||
| </Text> | ||
| </Pressable> | ||
|
|
||
| <Pressable | ||
| disabled={!canSubmit} | ||
| onPress={continueToOfficialBooking} | ||
| style={{ | ||
| backgroundColor: canSubmit ? Colors.accent : Colors.cardHover, | ||
| opacity: canSubmit ? 1 : 0.55, | ||
| borderRadius: 14, | ||
| padding: 16, | ||
| marginTop: 16, | ||
| alignItems: "center", | ||
| flexDirection: "row", | ||
| justifyContent: "center", | ||
| gap: 8, | ||
| }} | ||
| > | ||
| <Feather | ||
| name="external-link" | ||
| size={16} | ||
| color={canSubmit ? Colors.bg : Colors.muted} | ||
| /> | ||
| <Text | ||
| style={{ | ||
| color: canSubmit ? Colors.bg : Colors.muted, | ||
| fontFamily: Fonts.bodySemiBold, | ||
| fontSize: 13, | ||
| }} | ||
| > | ||
| Review Policies & Reserve | ||
| </Text> | ||
| </Pressable> | ||
|
|
||
| {status === "sent" && ( | ||
| <Pressable | ||
| onPress={() => setStatus("done")} | ||
| style={{ | ||
| borderColor: Colors.accentBorder, | ||
| borderWidth: 1, | ||
| borderRadius: 14, | ||
| padding: 14, | ||
| marginTop: 12, | ||
| alignItems: "center", | ||
| }} | ||
| > | ||
| <Text | ||
| style={{ | ||
| color: Colors.accent, | ||
| fontFamily: Fonts.bodySemiBold, | ||
| fontSize: 12, | ||
| }} | ||
| > | ||
| I completed my LibCal reservation | ||
| </Text> | ||
| </Pressable> | ||
| )} | ||
|
|
||
| <Pressable | ||
| onPress={() => Linking.openURL(LIBCAL_DIRECT_URL)} | ||
| style={{ padding: 14, alignItems: "center" }} | ||
| > | ||
| <Text | ||
| style={{ | ||
| color: Colors.muted, | ||
| fontFamily: Fonts.body, | ||
| fontSize: 12, | ||
| }} | ||
| > | ||
| Open LibCal directly | ||
| </Text> | ||
| </Pressable> | ||
| </ScrollView> | ||
| </SafeAreaView> |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
# First, check if the file exists and get its size
wc -l app/\(tabs\)/library.tsx 2>/dev/null || find . -name "library.tsx" -path "*/tabs/*" | head -5Repository: lebuckman/broncopath
Length of output: 91
🏁 Script executed:
# Read the file sections mentioned in the review comment
sed -n '97,341p' app/\(tabs\)/library.tsxRepository: lebuckman/broncopath
Length of output: 6967
🏁 Script executed:
# Read the second segment mentioned in the review
sed -n '345,514p' app/\(tabs\)/library.tsxRepository: lebuckman/broncopath
Length of output: 3989
🏁 Script executed:
# Check imports at the top of the file to see NativeWind usage
head -30 app/\(tabs\)/library.tsxRepository: lebuckman/broncopath
Length of output: 955
🏁 Script executed:
# Search for className usage in tab screens to see if NativeWind is actually being used
find app/\(tabs\) -name "*.tsx" | head -10Repository: lebuckman/broncopath
Length of output: 171
🏁 Script executed:
# Check if other tab screens use className
for file in app/\(tabs\)/index.tsx app/\(tabs\)/map.tsx app/\(tabs\)/rooms.tsx; do
echo "=== $file ==="
grep -c "className" "$file" || echo "0"
doneRepository: lebuckman/broncopath
Length of output: 157
🏁 Script executed:
# Check a sample of className usage in one of the other tab screens
sed -n '1,100p' app/\(tabs\)/index.tsx | grep -A2 "className"Repository: lebuckman/broncopath
Length of output: 723
Refactor component styling to use NativeWind className for layout and spacing
This file uses inline style objects exclusively. Per coding guidelines and the pattern established in other tab screens (index.tsx, rooms.tsx, map.tsx), layout properties (flex, flexDirection, padding, gap, margin, alignItems, justifyContent) must be moved to className, while dynamic colors and fontFamily remain in style.
Example from index.tsx showing correct pattern
<View
className="flex-1 gap-2.5 mb-8"
style={{ backgroundColor: Colors.bg }}
>
<Text
className="text-[12px]"
style={{ color: Colors.muted, fontFamily: Fonts.body }}
>Applies to: main content section (97-341) and all helper components (345-514).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/`(tabs)/library.tsx around lines 97 - 341, The file uses inline style
objects for layout and spacing; refactor layout props (flex, flexDirection,
padding, gap, margin, alignItems, justifyContent, flexWrap, etc.) into
NativeWind className strings while keeping dynamic colors and fontFamily in
style. For the main screen, update SafeAreaView, ScrollView, the heading Texts,
the container Views (the reservation draft box and form rows), Horizontal, and
all Pressable buttons (including the policy toggle, submit Pressable and direct
LibCal link) to use className for spacing/layout and preserve color/fontFamily
in their style props; do the same for helper components referenced later (Chip,
Toggle, Summary, Label) so only layout moves to className and color/fontFamily
remain in style. Ensure className values reflect the existing layout (e.g.,
padding, margin, flex, gap, flex-row, flex-wrap, items-center, justify-center)
and remove those layout properties from style objects.
There was a problem hiding this comment.
fr tho where is my beloved nativewind
There was a problem hiding this comment.
@lebuckman — right?! 😄 The new library.tsx is the odd one out — every other tab uses NativeWind className for layout/spacing while keeping dynamic colors and fontFamily in style, but this file went full inline-style for everything.
If you'd like, I can plan the refactor to bring it in line with the rest of the codebase — moving layout props like flex, flexDirection, padding, gap, margin, alignItems, justifyContent, flexWrap, etc. into className strings (e.g. className="flex-1 flex-row flex-wrap gap-2 p-4") while keeping Colors.* and Fonts.* references in style. That covers both the main LibraryTab component and all the local helper components (Chip, Toggle, Label, Horizontal, Summary, InfoCard).
Just say the word and I'll kick off the planning! 🐇✨
| "react": "19.2.0", | ||
| "react-dom": "19.2.0", | ||
| "react-native": "0.83.6", | ||
| "react-native-is-edge-to-edge": "^1.3.1", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== package.json versions =="
jq -r '.dependencies | {expo, react, "react-native", "react-native-is-edge-to-edge"}' package.json
echo
echo "== npm registry peerDependencies for react-native-is-edge-to-edge@1.3.1 =="
curl -s https://registry.npmjs.org/react-native-is-edge-to-edge/1.3.1 | jq -r '.peerDependencies // {}'
echo
echo "== lockfile presence/resolution check =="
LOCKFILE="$(fd -HI '^package-lock\.json$' | head -n 1 || true)"
if [ -z "${LOCKFILE}" ]; then
echo "package-lock.json not found"
else
echo "Found: ${LOCKFILE}"
jq -r '
.packages["node_modules/react-native-is-edge-to-edge"].version // "NOT_RESOLVED_IN_LOCKFILE"
' "${LOCKFILE}"
fiRepository: lebuckman/broncopath
Length of output: 428
Run npm install to regenerate the lockfile before merge.
The new dependency react-native-is-edge-to-edge@^1.3.1 has been added to package.json but is not yet resolved in backend/package-lock.json. Peer dependencies are satisfied (react * and react-native * align with your installed React 19.2.0 and React Native 0.83.6), but the lockfile must be updated to ensure consistent installs in CI/production.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@package.json` at line 40, package.json now lists the new dependency
react-native-is-edge-to-edge@^1.3.1 but the backend/package-lock.json was not
updated; run npm install in the backend to regenerate the lockfile so the new
dependency is resolved and committed, then verify package-lock.json reflects
react-native-is-edge-to-edge and include the updated lockfile in the PR before
merging.
lebuckman
left a comment
There was a problem hiding this comment.
look into CR's URL-launch failure comment and local date key comments to verify its validity
rest lgtm, just restructure the inconsistencies if you wanted to look into that too
| function getDays() { | ||
| return Array.from({ length: 7 }, (_, i) => { | ||
| const d = new Date(); | ||
| d.setDate(d.getDate() + i); |
There was a problem hiding this comment.
| d.setDate(d.getDate() + i); | |
| d.setDate(d.getDate() + i); | |
| const localDate = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`; |
| const d = new Date(); | ||
| d.setDate(d.getDate() + i); | ||
| return { | ||
| value: d.toISOString().slice(0, 10), |
There was a problem hiding this comment.
| value: d.toISOString().slice(0, 10), | |
| value: localDate, |
| async function continueToOfficialBooking() { | ||
| if (!validGroup) { | ||
| Alert.alert( | ||
| "Invalid group size", | ||
| "CPP group study rooms require 2 to 9 students." | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| if (!policy) { | ||
| Alert.alert( | ||
| "Policy confirmation required", | ||
| "Confirm that you understand CPP Library policies before continuing." | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| setStatus("sent"); | ||
| await Linking.openURL(CPP_RESERVE_URL); | ||
| } |
| <SafeAreaView edges={["top"]} style={{ flex: 1, backgroundColor: Colors.bg }}> | ||
| <ScrollView contentContainerStyle={{ padding: 20, paddingBottom: 44 }}> | ||
| <Text | ||
| style={{ | ||
| color: Colors.text, | ||
| fontFamily: Fonts.display, | ||
| fontSize: 28, | ||
| }} | ||
| > | ||
| Library Rooms | ||
| </Text> | ||
|
|
||
| <Text | ||
| style={{ | ||
| color: Colors.muted, | ||
| fontFamily: Fonts.body, | ||
| fontSize: 12, | ||
| marginTop: 4, | ||
| marginBottom: 18, | ||
| }} | ||
| > | ||
| Build your reservation, then finish through CPP SSO. | ||
| </Text> | ||
|
|
||
| <InfoCard status={status} /> | ||
|
|
||
| <Label icon="calendar">Date</Label> | ||
| <Horizontal> | ||
| {days.map((d) => ( | ||
| <Chip | ||
| key={d.value} | ||
| label={d.label} | ||
| selected={date === d.value} | ||
| onPress={() => setDate(d.value)} | ||
| /> | ||
| ))} | ||
| </Horizontal> | ||
|
|
||
| <Label icon="clock">Start time</Label> | ||
| <Horizontal> | ||
| {TIMES.map((t) => ( | ||
| <Chip | ||
| key={t} | ||
| label={t} | ||
| selected={time === t} | ||
| onPress={() => setTime(t)} | ||
| /> | ||
| ))} | ||
| </Horizontal> | ||
|
|
||
| <Label icon="watch">Duration</Label> | ||
| <View style={{ flexDirection: "row", flexWrap: "wrap", gap: 8 }}> | ||
| {DURATIONS.map((d) => ( | ||
| <Chip | ||
| key={d.value} | ||
| label={d.label} | ||
| selected={duration === d.value} | ||
| onPress={() => setDuration(d.value)} | ||
| /> | ||
| ))} | ||
| </View> | ||
|
|
||
| <Label icon="users">Group size</Label> | ||
| <TextInput | ||
| value={groupSize} | ||
| onChangeText={setGroupSize} | ||
| keyboardType="number-pad" | ||
| placeholder="2-9" | ||
| placeholderTextColor={Colors.muted} | ||
| style={{ | ||
| backgroundColor: Colors.card, | ||
| borderColor: validGroup ? Colors.border : Colors.highBorder, | ||
| borderWidth: 1, | ||
| borderRadius: 14, | ||
| color: Colors.text, | ||
| fontFamily: Fonts.body, | ||
| padding: 14, | ||
| marginBottom: 6, | ||
| }} | ||
| /> | ||
|
|
||
| <Label icon="layers">Preferred floor</Label> | ||
| <View style={{ flexDirection: "row", flexWrap: "wrap", gap: 8 }}> | ||
| {FLOORS.map((f) => ( | ||
| <Chip | ||
| key={f} | ||
| label={f === "Any" ? "Any floor" : `Floor ${f}`} | ||
| selected={floor === f} | ||
| onPress={() => setFloor(f)} | ||
| /> | ||
| ))} | ||
| </View> | ||
|
|
||
| <Label icon="sliders">Preferences</Label> | ||
| <Toggle | ||
| label="Power outlet preferred" | ||
| value={power} | ||
| onPress={() => setPower(!power)} | ||
| /> | ||
| <Toggle | ||
| label="ADA-accessible room preferred" | ||
| value={ada} | ||
| onPress={() => setAda(!ada)} | ||
| /> | ||
|
|
||
| <View | ||
| style={{ | ||
| backgroundColor: Colors.surface, | ||
| borderColor: Colors.border, | ||
| borderWidth: 1, | ||
| borderRadius: 18, | ||
| padding: 16, | ||
| marginTop: 16, | ||
| }} | ||
| > | ||
| <Text | ||
| style={{ | ||
| color: Colors.text, | ||
| fontFamily: Fonts.bodySemiBold, | ||
| fontSize: 14, | ||
| marginBottom: 10, | ||
| }} | ||
| > | ||
| Reservation draft | ||
| </Text> | ||
|
|
||
| <Summary label="Date" value={date} /> | ||
| <Summary label="Time" value={time} /> | ||
| <Summary label="Duration" value={`${duration} minutes`} /> | ||
| <Summary label="Group" value={`${groupSize} students`} /> | ||
| <Summary | ||
| label="Needs" | ||
| value={[ | ||
| floor === "Any" ? "Any floor" : `Floor ${floor}`, | ||
| power ? "Power outlet" : null, | ||
| ada ? "ADA" : null, | ||
| ] | ||
| .filter(Boolean) | ||
| .join(" · ")} | ||
| /> | ||
| </View> | ||
|
|
||
| <Pressable | ||
| onPress={() => setPolicy(!policy)} | ||
| style={{ | ||
| backgroundColor: policy ? Colors.accentBg : Colors.card, | ||
| borderColor: policy ? Colors.accentBorder : Colors.border, | ||
| borderWidth: 1, | ||
| borderRadius: 18, | ||
| padding: 16, | ||
| marginTop: 14, | ||
| flexDirection: "row", | ||
| gap: 12, | ||
| }} | ||
| > | ||
| <Feather | ||
| name={policy ? "check-square" : "square"} | ||
| size={22} | ||
| color={policy ? Colors.accent : Colors.muted} | ||
| /> | ||
| <Text | ||
| style={{ | ||
| color: Colors.text, | ||
| fontFamily: Fonts.body, | ||
| fontSize: 12, | ||
| lineHeight: 18, | ||
| flex: 1, | ||
| }} | ||
| > | ||
| I understand final booking must be completed through CPP Library, | ||
| including policy agreement and CPP SSO. | ||
| </Text> | ||
| </Pressable> | ||
|
|
||
| <Pressable | ||
| disabled={!canSubmit} | ||
| onPress={continueToOfficialBooking} | ||
| style={{ | ||
| backgroundColor: canSubmit ? Colors.accent : Colors.cardHover, | ||
| opacity: canSubmit ? 1 : 0.55, | ||
| borderRadius: 14, | ||
| padding: 16, | ||
| marginTop: 16, | ||
| alignItems: "center", | ||
| flexDirection: "row", | ||
| justifyContent: "center", | ||
| gap: 8, | ||
| }} | ||
| > | ||
| <Feather | ||
| name="external-link" | ||
| size={16} | ||
| color={canSubmit ? Colors.bg : Colors.muted} | ||
| /> | ||
| <Text | ||
| style={{ | ||
| color: canSubmit ? Colors.bg : Colors.muted, | ||
| fontFamily: Fonts.bodySemiBold, | ||
| fontSize: 13, | ||
| }} | ||
| > | ||
| Review Policies & Reserve | ||
| </Text> | ||
| </Pressable> | ||
|
|
||
| {status === "sent" && ( | ||
| <Pressable | ||
| onPress={() => setStatus("done")} | ||
| style={{ | ||
| borderColor: Colors.accentBorder, | ||
| borderWidth: 1, | ||
| borderRadius: 14, | ||
| padding: 14, | ||
| marginTop: 12, | ||
| alignItems: "center", | ||
| }} | ||
| > | ||
| <Text | ||
| style={{ | ||
| color: Colors.accent, | ||
| fontFamily: Fonts.bodySemiBold, | ||
| fontSize: 12, | ||
| }} | ||
| > | ||
| I completed my LibCal reservation | ||
| </Text> | ||
| </Pressable> | ||
| )} | ||
|
|
||
| <Pressable | ||
| onPress={() => Linking.openURL(LIBCAL_DIRECT_URL)} | ||
| style={{ padding: 14, alignItems: "center" }} | ||
| > | ||
| <Text | ||
| style={{ | ||
| color: Colors.muted, | ||
| fontFamily: Fonts.body, | ||
| fontSize: 12, | ||
| }} | ||
| > | ||
| Open LibCal directly | ||
| </Text> | ||
| </Pressable> | ||
| </ScrollView> | ||
| </SafeAreaView> |
There was a problem hiding this comment.
fr tho where is my beloved nativewind
Summary by CodeRabbit