Skip to content

Commit 3b3495c

Browse files
committed
redesign building card component according to figma
1 parent 9ec40ff commit 3b3495c

217 files changed

Lines changed: 269 additions & 70 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

frontend/components/BuildingCard.tsx

Lines changed: 197 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import StarIcon from "@mui/icons-material/Star";
2-
import { Typography } from "@mui/material";
2+
import { Typography, TypographyProps } from "@mui/material";
33
import Box, { BoxProps } from "@mui/material/Box";
44
import CircularProgress from "@mui/material/CircularProgress";
55
import Stack from "@mui/material/Stack";
@@ -14,19 +14,20 @@ import { setCurrentBuilding } from "../redux/currentBuildingSlice";
1414
import { useDispatch } from "../redux/hooks";
1515
import { getNumFreerooms } from "../utils/utils";
1616
import StatusDot from "./StatusDot";
17+
import BuildingRating from "./Rating/BuildingRating";
18+
19+
import { useMediaQuery } from "@mui/material";
1720

1821
const INITIALISING = -2;
1922
const FAILED = -1;
2023

2124
const MainBox = styled(Box)<BoxProps>(({ theme }) => ({
22-
position: "relative",
23-
flex: 1,
24-
backgroundColor: theme.palette.primary.main,
25-
height: 385,
26-
borderRadius: 10,
27-
"&:hover": {
28-
cursor: "pointer",
29-
},
25+
display: "flex",
26+
flexDirection: "column",
27+
height: 379,
28+
borderRadius: 12,
29+
border: "1px solid #F3D0C5",
30+
overflow: "hidden",
3031
[theme.breakpoints.down("lg")]: {
3132
height: 300,
3233
},
@@ -35,8 +36,16 @@ const MainBox = styled(Box)<BoxProps>(({ theme }) => ({
3536
},
3637
}));
3738

39+
const ImageBox = styled(Box)<BoxProps>(({ theme }) => ({
40+
position: "relative",
41+
height: 249,
42+
borderTopLeftRadius: 12,
43+
borderTopRightRadius: 12,
44+
cursor: "pointer",
45+
//width: "100%",
46+
}));
47+
3848
const StyledImage = styled(Image)<ImageProps>(({ theme }) => ({
39-
borderRadius: 10,
4049
transition: "all 0.1s ease-in-out",
4150
"&:hover": {
4251
opacity: 0.7,
@@ -47,39 +56,66 @@ const StatusBox = styled(Box)<BoxProps>(({ theme }) => ({
4756
display: "flex",
4857
justifyContent: "center",
4958
alignItems: "center",
50-
borderRadius: 15,
59+
borderRadius: 100,
5160
position: "absolute",
5261
top: 0,
5362
right: 0,
54-
padding: 10,
55-
paddingLeft: 15,
56-
paddingRight: 15,
63+
padding: 6,
64+
paddingLeft: 12,
65+
paddingRight: 12,
5766
margin: 10,
67+
gap: 6,
5868
pointerEvents: "none",
5969
backgroundColor: theme.palette.background.default,
6070
}));
6171

62-
const TitleBox = styled(Box)<BoxProps>(({ theme }) => ({
72+
const InfoBox = styled(Box)<BoxProps>(({ theme }) => ({
73+
display: "flex",
74+
flexDirection: "column",
75+
borderBottomLeftRadius: 12,
76+
borderBottomRightRadius: 12,
77+
padding: 12,
78+
gap: 4,
79+
//width: "100%",
80+
}));
81+
82+
const InfoFooterBox = styled(Box)<BoxProps>(({ theme }) => ({
6383
display: "flex",
64-
borderRadius: 10,
65-
position: "absolute",
6684
justifyContent: "space-between",
67-
bottom: 0,
68-
left: 0,
69-
right: 0,
70-
backgroundColor: theme.palette.primary.main,
71-
color: "white",
72-
padding: 15,
73-
paddingLeft: 20,
74-
paddingRight: 20,
75-
margin: 10,
76-
pointerEvents: "none",
85+
paddingTop: 8,
86+
}));
87+
88+
const DetailPill = styled(Box)<BoxProps>(({ theme }) => ({
89+
borderRadius: 100,
90+
gap: 6,
91+
padding: 6,
92+
paddingLeft: 12,
93+
paddingRight: 12,
94+
backgroundColor: "#FDE7E1",
95+
}));
96+
97+
const DetailPillText = styled(Typography)<TypographyProps>(() => ({
98+
fontFamily: "TT Commons Pro Trial Variable",
99+
fontSize: 12,
100+
fontWeight: 400,
101+
color: "#D4613C",
102+
paddingBottom: "2px",
103+
gap: 10,
104+
}));
105+
106+
// Show only building name and rating for smaller screens
107+
const NameRatingBox = styled(Box)<BoxProps>(({ theme }) => ({
108+
display: "flex",
109+
flexDirection: "row",
110+
justifyContent: "space-between",
111+
alignItems: "center",
77112
}));
78113

79114
const BuildingCard: React.FC<{
80115
buildingId: string;
81116
}> = ({ buildingId }) => {
82117
const dispatch = useDispatch();
118+
const isCompact = useMediaQuery("(max-width:900px)");
83119

84120
const { building } = useBuilding(buildingId);
85121
const { status } = useBuildingStatus(buildingId);
@@ -91,49 +127,144 @@ const BuildingCard: React.FC<{
91127

92128
return (
93129
<MainBox onClick={() => dispatch(setCurrentBuilding(building))}>
94-
<StyledImage
95-
alt={`Image of ${buildingId}`}
96-
src={`/assets/building_photos/${buildingId}.webp`}
97-
fill={true}
98-
style={{ objectFit: "cover" }}
99-
priority={true}
100-
/>
101-
<StatusBox>
102-
{freerooms > INITIALISING ? (
130+
<ImageBox>
131+
<StyledImage
132+
alt={`Image of ${buildingId}`}
133+
src={`/assets/building_photos/${buildingId}.webp`}
134+
fill={true}
135+
style={{ objectFit: "cover" }}
136+
priority={true}
137+
/>
138+
<StatusBox>
139+
{freerooms > INITIALISING ? (
140+
<>
141+
{freerooms !== FAILED ? (
142+
<StatusDot
143+
colour={
144+
freerooms >= 5
145+
? "green"
146+
: freerooms !== 0
147+
? "orange"
148+
: "red"
149+
}
150+
/>
151+
) : null}
152+
<Typography
153+
sx={{
154+
fontFamily: "TT Commons Pro Trial Variable",
155+
fontWeight: 400,
156+
fontSize: 12,
157+
paddingBottom: "2px",
158+
}}
159+
>
160+
{freerooms !== FAILED
161+
? `${freerooms} room${freerooms === 1 ? "" : "s"} available`
162+
: "Data Unavailable"}
163+
</Typography>
164+
</>
165+
) : (
166+
<CircularProgress size={20} thickness={5} disableShrink />
167+
)}
168+
</StatusBox>
169+
</ImageBox>
170+
171+
<InfoBox>
172+
{isCompact ? (
173+
<NameRatingBox>
174+
<Typography
175+
sx={{
176+
fontFamily: "TT Commons Pro Trial Variable",
177+
fontWeight: 700,
178+
fontSize: 20,
179+
color: "#632410",
180+
textTransform: "uppercase",
181+
overflow: "hidden",
182+
textOverflow: "ellipsis",
183+
whiteSpace: "nowrap",
184+
}}
185+
>
186+
{building.name}
187+
</Typography>
188+
189+
<Stack
190+
direction="row"
191+
alignItems="center"
192+
spacing="1px"
193+
aria-label="star-info"
194+
>
195+
<Typography
196+
sx={{
197+
fontFamily: "TT Commons Pro Trial Variable",
198+
fontWeight: 400,
199+
fontSize: 12,
200+
color: "#D4613C",
201+
}}
202+
>
203+
{ratings?.overallRating}
204+
</Typography>
205+
206+
<StarIcon sx={{ color: "#D4613C" }} />
207+
</Stack>
208+
</NameRatingBox>
209+
) : (
103210
<>
104-
{freerooms !== FAILED ? (
105-
<StatusDot
106-
colour={
107-
freerooms >= 5 ? "green" : freerooms !== 0 ? "orange" : "red"
108-
}
109-
/>
110-
) : null}
111-
<Typography sx={{ fontSize: 12, fontWeight: 500 }}>
112-
{freerooms !== FAILED
113-
? `${freerooms} room${freerooms === 1 ? "" : "s"} available`
114-
: "Data Unavailable"}
211+
<Typography
212+
sx={{
213+
fontFamily: "TT Commons Pro Trial Variable",
214+
fontWeight: 400,
215+
fontSize: 12,
216+
color: "#D4613C",
217+
}}
218+
>
219+
{`Building ID ${buildingId}`}
220+
</Typography>
221+
222+
<Typography
223+
sx={{
224+
fontFamily: "TT Commons Pro Trial Variable",
225+
fontWeight: 700,
226+
fontSize: 20,
227+
color: "#632410",
228+
textTransform: "uppercase",
229+
overflow: "hidden",
230+
textOverflow: "ellipsis",
231+
whiteSpace: "nowrap",
232+
}}
233+
>
234+
{building.name}
115235
</Typography>
236+
237+
<Stack
238+
direction="row"
239+
alignItems="center"
240+
gap="1px"
241+
aria-label="star-info"
242+
>
243+
<BuildingRating overallRating={ratings?.overallRating ?? 0} />
244+
</Stack>
245+
246+
<InfoFooterBox>
247+
<Stack direction="row" gap="8px">
248+
<DetailPill>
249+
<DetailPillText>Category</DetailPillText>
250+
</DetailPill>
251+
252+
<DetailPill>
253+
<DetailPillText>TODO</DetailPillText>
254+
</DetailPill>
255+
</Stack>
256+
257+
<Image
258+
alt="Arrow up right icon"
259+
src="/assets/icons/arrow-up-right.svg"
260+
width={24}
261+
height={24}
262+
style={{ cursor: "pointer" }}
263+
/>
264+
</InfoFooterBox>
116265
</>
117-
) : (
118-
<CircularProgress size={20} thickness={5} disableShrink />
119266
)}
120-
</StatusBox>
121-
<TitleBox>
122-
<Typography sx={{ fontSize: 16, fontWeight: 500 }}>
123-
{building.name}
124-
</Typography>
125-
<Stack
126-
direction="row"
127-
alignItems="center"
128-
spacing={0.3}
129-
aria-label="star-info"
130-
>
131-
<Typography sx={{ fontSize: 16, fontWeight: 500 }}>
132-
{ratings?.overallRating}
133-
</Typography>
134-
<StarIcon sx={{ color: "rgb(255, 169, 12)" }} />
135-
</Stack>
136-
</TitleBox>
267+
</InfoBox>
137268
</MainBox>
138269
);
139270
};
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import React from "react";
2+
3+
export default function BuildingRating({
4+
overallRating,
5+
}: {
6+
overallRating: number;
7+
}) {
8+
const content = "★★★★★";
9+
10+
return (
11+
<div
12+
style={{
13+
position: "relative",
14+
display: "inline-block",
15+
color: "#ccc",
16+
}}
17+
>
18+
<span aria-label="rating">{content}</span>
19+
20+
<span
21+
style={{
22+
width: `${(overallRating / 5) * 100}%`,
23+
color: "#D4613C",
24+
overflow: "hidden",
25+
position: "absolute",
26+
top: 0,
27+
left: 0,
28+
whiteSpace: "nowrap",
29+
}}
30+
aria-hidden={true}
31+
>
32+
{content}
33+
</span>
34+
</div>
35+
);
36+
}

frontend/components/StatusDot.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,15 @@ const StatusDot: React.FC<{ colour: "green" | "orange" | "red" }> = ({
66
return (
77
<Box
88
sx={(theme) => ({
9-
width: 10,
10-
height: 10,
9+
width: 8,
10+
height: 8,
1111
borderRadius: "50%",
1212
backgroundColor:
1313
colour === "green"
1414
? theme.palette.success.light
1515
: colour === "orange"
1616
? theme.palette.warning.light
1717
: theme.palette.error.light,
18-
marginRight: theme.spacing(1.25),
1918
})}
2019
/>
2120
);
Lines changed: 4 additions & 0 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)