Skip to content

Commit a200011

Browse files
authored
Merge pull request #157 from GenerateNU/spoilers_v2
FE: Spoilers
2 parents a1dc61e + f04ef02 commit a200011

6 files changed

Lines changed: 595 additions & 271 deletions

File tree

backend/prisma/seed.sql

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,19 @@ INSERT INTO "public"."UserProfile" (
4545
"favoriteGenres",
4646
"favoriteMovies",
4747
"createdAt",
48-
"updatedAt"
48+
"updatedAt",
49+
"spoiler"
4950
) VALUES
50-
('11111111-1111-1111-1111-111111111111', 'alice_movie_fan', true, 'English', ARRAY['Spanish'], NULL, 'USA', 'New York', ARRAY['Drama', 'Thriller'], ARRAY['tt0111161', 'tt0068646'], NOW(), NOW()),
51-
('22222222-2222-2222-2222-222222222222', 'bob_cineaste', true, 'English', ARRAY['French'], NULL, 'USA', 'Los Angeles', ARRAY['Action', 'Sci-Fi'], ARRAY['tt0468569', 'tt0137523'], NOW(), NOW()),
52-
('33333333-3333-3333-3333-333333333333', 'charlie_critic', true, 'English', ARRAY[]::text[], NULL, 'Canada', 'Toronto', ARRAY['Comedy', 'Romance'], ARRAY['tt0109830', 'tt1375666'], NOW(), NOW()),
53-
('44444444-4444-4444-4444-444444444444', 'diana_director', true, 'English', ARRAY['Italian'], NULL, 'Italy', 'Rome', ARRAY['Drama', 'Biography'], ARRAY['tt0073486', 'tt0099685'], NOW(), NOW()),
54-
('55555555-5555-5555-5555-555555555555', 'evan_enthusiast', true, 'English', ARRAY['Japanese'], NULL, 'USA', 'San Francisco', ARRAY['Animation', 'Fantasy'], ARRAY['tt0245429', 'tt1853728'], NOW(), NOW()),
55-
('66666666-6666-6666-6666-666666666666', 'fiona_film_buff', true, 'English', ARRAY['German'], NULL, 'Germany', 'Berlin', ARRAY['Horror', 'Mystery'], ARRAY['tt0816692', 'tt0110912'], NOW(), NOW()),
56-
('77777777-7777-7777-7777-777777777777', 'george_genre_fan', true, 'English', ARRAY[]::text[], NULL, 'USA', 'Chicago', ARRAY['Western', 'Crime'], ARRAY['tt0076759', 'tt0050083'], NOW(), NOW()),
57-
('88888888-8888-8888-8888-888888888888', 'hannah_hollywood', true, 'English', ARRAY['Korean'], NULL, 'South Korea', 'Seoul', ARRAY['Drama', 'Thriller'], ARRAY['tt6751668', 'tt0167260'], NOW(), NOW()),
58-
('99999999-9999-9999-9999-999999999999', 'isaac_indie', true, 'English', ARRAY[]::text[], NULL, 'UK', 'London', ARRAY['Independent', 'Documentary'], ARRAY['tt0114369', 'tt0120737'], NOW(), NOW()),
59-
('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'julia_junkie', true, 'English', ARRAY['Portuguese'], NULL, 'Brazil', 'São Paulo', ARRAY['Drama', 'Romance'], ARRAY['tt0133093', 'tt0088763'], NOW(), NOW())
51+
('11111111-1111-1111-1111-111111111111', 'alice_movie_fan', true, 'English', ARRAY['Spanish'], NULL, 'USA', 'New York', ARRAY['Drama', 'Thriller'], ARRAY['tt0111161', 'tt0068646'], NOW(), NOW(), false),
52+
('22222222-2222-2222-2222-222222222222', 'bob_cineaste', true, 'English', ARRAY['French'], NULL, 'USA', 'Los Angeles', ARRAY['Action', 'Sci-Fi'], ARRAY['tt0468569', 'tt0137523'], NOW(), NOW(), false),
53+
('33333333-3333-3333-3333-333333333333', 'charlie_critic', true, 'English', ARRAY[]::text[], NULL, 'Canada', 'Toronto', ARRAY['Comedy', 'Romance'], ARRAY['tt0109830', 'tt1375666'], NOW(), NOW(), false),
54+
('44444444-4444-4444-4444-444444444444', 'diana_director', true, 'English', ARRAY['Italian'], NULL, 'Italy', 'Rome', ARRAY['Drama', 'Biography'], ARRAY['tt0073486', 'tt0099685'], NOW(), NOW(), false),
55+
('55555555-5555-5555-5555-555555555555', 'evan_enthusiast', true, 'English', ARRAY['Japanese'], NULL, 'USA', 'San Francisco', ARRAY['Animation', 'Fantasy'], ARRAY['tt0245429', 'tt1853728'], NOW(), NOW(), false),
56+
('66666666-6666-6666-6666-666666666666', 'fiona_film_buff', true, 'English', ARRAY['German'], NULL, 'Germany', 'Berlin', ARRAY['Horror', 'Mystery'], ARRAY['tt0816692', 'tt0110912'], NOW(), NOW(), false),
57+
('77777777-7777-7777-7777-777777777777', 'george_genre_fan', true, 'English', ARRAY[]::text[], NULL, 'USA', 'Chicago', ARRAY['Western', 'Crime'], ARRAY['tt0076759', 'tt0050083'], NOW(), NOW(), false),
58+
('88888888-8888-8888-8888-888888888888', 'hannah_hollywood', true, 'English', ARRAY['Korean'], NULL, 'South Korea', 'Seoul', ARRAY['Drama', 'Thriller'], ARRAY['tt6751668', 'tt0167260'], NOW(), NOW(), false),
59+
('99999999-9999-9999-9999-999999999999', 'isaac_indie', true, 'English', ARRAY[]::text[], NULL, 'UK', 'London', ARRAY['Independent', 'Documentary'], ARRAY['tt0114369', 'tt0120737'], NOW(), NOW(), false),
60+
('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'julia_junkie', true, 'English', ARRAY['Portuguese'], NULL, 'Brazil', 'São Paulo', ARRAY['Drama', 'Romance'], ARRAY['tt0133093', 'tt0088763'], NOW(), NOW(), false)
6061
ON CONFLICT ("userId") DO NOTHING;
6162

6263
-- ============================================

frontend/components/PicturePost.tsx

Lines changed: 103 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -6,91 +6,116 @@ import MyCarousel from './Carousel';
66
const { width } = Dimensions.get('window');
77

88
type PicturePostProps = {
9-
userName: string;
10-
username: string;
11-
date: string;
12-
avatarUri?: string;
13-
content: string;
14-
imageUrls?: string[];
15-
userId?: string;
9+
userName: string;
10+
username: string;
11+
date: string;
12+
avatarUri?: string;
13+
content: string;
14+
imageUrls?: string[];
15+
userId?: string;
16+
/** If true, show a 'Spoiler' badge on the card */
17+
spoiler?: boolean;
1618
};
1719

1820
export default function PicturePost({
19-
userName,
20-
username,
21-
date,
22-
avatarUri,
23-
content,
24-
imageUrls = [],
25-
userId,
21+
userName,
22+
username,
23+
date,
24+
avatarUri,
25+
content,
26+
imageUrls = [],
27+
userId,
28+
spoiler = false,
2629
}: PicturePostProps) {
27-
const imageComponents = imageUrls.map((url, index) => (
28-
<Image
29-
source={{ uri: url }}
30-
style={styles.image}
31-
resizeMode="cover"
32-
key={`image-${index}`}
33-
/>
34-
));
30+
const imageComponents = imageUrls.map((url, index) => (
31+
<Image
32+
source={{ uri: url }}
33+
style={styles.image}
34+
resizeMode="cover"
35+
key={`image-${index}`}
36+
/>
37+
));
3538

36-
return (
37-
<View style={styles.container}>
38-
<UserBar
39-
name={userName}
40-
username={username}
41-
date={date}
42-
avatarUri={avatarUri}
43-
userId={userId}
44-
/>
45-
<Text style={styles.content}>{content}</Text>
39+
return (
40+
<View style={styles.container}>
41+
{/* Top-right spoiler pill */}
42+
{spoiler && (
43+
<View style={styles.spoilerPill}>
44+
<Text style={styles.spoilerText}>Spoiler</Text>
45+
</View>
46+
)}
47+
48+
<UserBar
49+
name={userName}
50+
username={username}
51+
date={date}
52+
avatarUri={avatarUri}
53+
userId={userId}
54+
/>
55+
<Text style={styles.content}>{content}</Text>
4656

47-
{imageUrls.length > 0 ? (
48-
<MyCarousel
49-
components={imageComponents}
50-
width={100}
51-
height={40}
52-
/>
53-
) : (
54-
<View style={styles.imagePlaceholder}>
55-
<Text style={styles.placeholderText}>No Image</Text>
56-
</View>
57-
)}
57+
{imageUrls.length > 0 ? (
58+
<MyCarousel components={imageComponents} width={100} height={40} />
59+
) : (
60+
<View style={styles.imagePlaceholder}>
61+
<Text style={styles.placeholderText}>No Image</Text>
5862
</View>
59-
);
63+
)}
64+
</View>
65+
);
6066
}
6167

6268
const styles = StyleSheet.create({
63-
container: {
64-
backgroundColor: '#FFF',
65-
borderRadius: width * 0.03,
66-
padding: width * 0.04,
67-
marginBottom: width * 0.04,
68-
width: '100%',
69-
},
70-
content: {
71-
fontSize: width * 0.0375,
72-
color: '#000',
73-
lineHeight: width * 0.05,
74-
marginTop: width * 0.03,
75-
marginBottom: width * 0.03,
76-
flexShrink: 1,
77-
},
78-
image: {
79-
width: '100%',
80-
height: '100%',
81-
borderRadius: width * 0.02,
82-
},
83-
imagePlaceholder: {
84-
width: '100%',
85-
aspectRatio: 16 / 9,
86-
backgroundColor: '#E8E8E8',
87-
borderRadius: width * 0.02,
88-
justifyContent: 'center',
89-
alignItems: 'center',
90-
marginBottom: width * 0.03,
91-
},
92-
placeholderText: {
93-
color: '#999',
94-
fontSize: width * 0.035,
95-
},
96-
});
69+
container: {
70+
backgroundColor: '#FFF',
71+
borderRadius: width * 0.03,
72+
padding: width * 0.04,
73+
marginBottom: width * 0.04,
74+
width: '100%',
75+
position: 'relative', // 👈 needed for pill positioning
76+
},
77+
content: {
78+
fontSize: width * 0.0375,
79+
color: '#000',
80+
lineHeight: width * 0.05,
81+
marginTop: width * 0.03,
82+
marginBottom: width * 0.03,
83+
flexShrink: 1,
84+
},
85+
image: {
86+
width: '100%',
87+
height: '100%',
88+
borderRadius: width * 0.02,
89+
},
90+
imagePlaceholder: {
91+
width: '100%',
92+
aspectRatio: 16 / 9,
93+
backgroundColor: '#E8E8E8',
94+
borderRadius: width * 0.02,
95+
justifyContent: 'center',
96+
alignItems: 'center',
97+
marginBottom: width * 0.03,
98+
},
99+
placeholderText: {
100+
color: '#999',
101+
fontSize: width * 0.035,
102+
},
103+
spoilerPill: {
104+
position: 'absolute',
105+
top: width * 0.025,
106+
right: width * 0.035,
107+
paddingHorizontal: 10,
108+
paddingVertical: 4,
109+
borderRadius: 999,
110+
backgroundColor: 'rgba(0,0,0,0.75)',
111+
borderWidth: 1,
112+
borderColor: '#F5C518',
113+
zIndex: 2,
114+
},
115+
spoilerText: {
116+
color: '#F5C518',
117+
fontSize: 11,
118+
fontWeight: '700',
119+
textTransform: 'uppercase',
120+
},
121+
});

frontend/components/ReviewPost.tsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ type ReviewPostProps = {
2828
reviewerUserId?: string;
2929
movieImageUrl: string;
3030
onPress?: () => void;
31+
/** If true, show a 'Spoiler' badge on the card */
32+
spoiler?: boolean;
3133
};
3234

3335
export default function ReviewPost({
@@ -43,6 +45,7 @@ export default function ReviewPost({
4345
reviewerUserId,
4446
movieImageUrl,
4547
onPress,
48+
spoiler = false,
4649
}: ReviewPostProps) {
4750
const content = (
4851
<View style={styles.container}>
@@ -52,6 +55,15 @@ export default function ReviewPost({
5255
imageStyle={styles.image}
5356
resizeMode="cover"
5457
>
58+
{/* Top overlay row (spoiler badge, etc.) */}
59+
<View style={styles.topOverlayRow}>
60+
{spoiler && (
61+
<View style={styles.spoilerPill}>
62+
<Text style={styles.spoilerText}>Spoiler</Text>
63+
</View>
64+
)}
65+
</View>
66+
5567
<View style={styles.bottomContainer}>
5668
<MaskedView
5769
style={styles.maskedView}
@@ -126,6 +138,30 @@ const styles = StyleSheet.create({
126138
image: {
127139
borderRadius: width * 0.03,
128140
},
141+
// row at the top of the card where the spoiler pill sits
142+
topOverlayRow: {
143+
position: 'absolute',
144+
top: width * 0.03,
145+
right: width * 0.03,
146+
left: width * 0.03,
147+
flexDirection: 'row',
148+
justifyContent: 'flex-end',
149+
zIndex: 2,
150+
},
151+
spoilerPill: {
152+
paddingHorizontal: 10,
153+
paddingVertical: 4,
154+
borderRadius: 999,
155+
backgroundColor: 'rgba(0,0,0,0.75)',
156+
borderWidth: 1,
157+
borderColor: '#F5C518', // IMDb-ish yellow accent
158+
},
159+
spoilerText: {
160+
color: '#F5C518',
161+
fontSize: 12,
162+
fontWeight: '700',
163+
textTransform: 'uppercase',
164+
},
129165
bottomContainer: {
130166
flex: 1,
131167
justifyContent: 'flex-end',

0 commit comments

Comments
 (0)