Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | 1x 20x 20x 20x 14x 6x 6x 24x 24x 12x 3x 9x 24x 11x 9x | import BasicLayout from "main/layouts/BasicLayout/BasicLayout";
import { useParams } from "react-router";
import { useQuery } from "react-query";
import axios from "axios";
import { toast } from "react-toastify";
import MealTable from "main/components/Meal/MealTable";
/* eslint-disable react-refresh/only-export-components*/
export const onMealsError = (error, diningCommonsCode, dateTime) => {
console.error("onMealsError: error=", error);
// Check if it's a specific error related to closed dining commons
// Stryker disable next-line all : Optional chaining on error.response?.status is defensive coding
const isClosedDiningCommons =
error.response?.status === 404 ||
error.response?.status === 500 ||
// Stryker disable next-line all : Optional chaining on error.response?.data?.message is defensive coding
error.response?.data?.message?.toLowerCase().includes("no meals") ||
// Stryker disable next-line all : Optional chaining on error.response?.data?.message is defensive coding
error.response?.data?.message?.toLowerCase().includes("closed");
if (isClosedDiningCommons) {
// Show user-friendly message for closed dining commons
toast.error(
`${diningCommonsCode} is not serving meals on ${dateTime}. Please try a different date or dining commons.`,
);
} else {
// Show generic error message for other types of errors
// Stryker disable all : Fallback message with OR operator and optional chaining is defensive coding
const message =
error.response?.data?.message ||
`Error loading meals for ${diningCommonsCode} on ${dateTime}`;
// Stryker restore all
toast.error(message);
}
};
/* eslint-enable react-refresh/only-export-components*/
export default function MealTimesPage() {
// Stryker disable next-line all : Can't test state because hook is internal
let { "date-time": dateTime, "dining-commons-code": diningCommonsCode } =
useParams();
const {
data: meals,
error,
isLoading,
} = useQuery(
// Stryker disable next-line all : don't test internal caching of React Query
[`/api/diningcommons/${dateTime}/${diningCommonsCode}`],
async () => {
const response = await axios.get(
`/api/diningcommons/${dateTime}/${diningCommonsCode}`,
);
return response.data;
},
{
retry: false,
// Stryker disable next-line all : onError callback is tested via component behavior tests
onError: (error) => {
// Use custom error handler instead of generic toast spam
onMealsError(error, diningCommonsCode, dateTime);
},
},
);
// Handle loading state
if (isLoading) {
return (
<BasicLayout>
<div className="pt-2">
<h1>
Meals at {diningCommonsCode} for {dateTime}
</h1>
<div className="text-center">
<div className="spinner-border" role="status">
<span className="visually-hidden">Loading...</span>
</div>
<p className="mt-2">Loading meal times...</p>
</div>
</div>
</BasicLayout>
);
}
// Handle error state (dining commons closed, network issues, etc.)
if (error) {
// Stryker disable next-line all : Optional chaining on error.response?.status is defensive coding
const isClosedDiningCommons =
error.response?.status === 404 ||
error.response?.status === 500 ||
// Stryker disable next-line all : Optional chaining on error.response?.data?.message is defensive coding
error.response?.data?.message?.toLowerCase().includes("no meals") ||
// Stryker disable next-line all : Optional chaining on error.response?.data?.message is defensive coding
error.response?.data?.message?.toLowerCase().includes("closed");
return (
<BasicLayout>
<div className="pt-2">
<h1>
Meals at {diningCommonsCode} for {dateTime}
</h1>
<div
className={`alert ${isClosedDiningCommons ? "alert-info" : "alert-danger"}`}
>
<h4>
{isClosedDiningCommons
? "No meals available"
: "Error loading meals"}
</h4>
<p>
{isClosedDiningCommons
? `${diningCommonsCode} is not serving meals on ${dateTime}.`
: "Unable to load meal information at this time."}
</p>
<p>
{isClosedDiningCommons
? "This dining commons may be closed on this date. Please try a different date or select another dining commons."
: "Please try again later or contact support if the problem persists."}
</p>
</div>
</div>
</BasicLayout>
);
}
return (
<BasicLayout>
<div className="pt-2">
{/* You can display all meal times of the dining common on a certain date */}
<h1>
Meals at {diningCommonsCode} for {dateTime}
</h1>
{meals && (
<MealTable
meals={meals}
dateTime={dateTime}
diningCommonsCode={diningCommonsCode}
/>
)}
</div>
</BasicLayout>
);
}
|