Compare commits
10 Commits
bf08eefe57
...
8f3e442077
Author | SHA1 | Date | |
---|---|---|---|
8f3e442077 | |||
0430710522 | |||
c1805643c8 | |||
f1c296c0d3 | |||
2041c8998a | |||
cff010f2b4 | |||
986aca3931 | |||
a57a059c2a | |||
b7dc6af2e4 | |||
4fc58aedd7 |
@ -18,6 +18,7 @@ new Docs(
|
|||||||
export async function add_post(req: Request, res: Response) {
|
export async function add_post(req: Request, res: Response) {
|
||||||
try {
|
try {
|
||||||
const data: IReview = req.body;
|
const data: IReview = req.body;
|
||||||
|
data.user_id = res.locals.user._id
|
||||||
const review = new Review(data);
|
const review = new Review(data);
|
||||||
await review.save();
|
await review.save();
|
||||||
res.status(201).json(Log.info(201, "review was added", review));
|
res.status(201).json(Log.info(201, "review was added", review));
|
||||||
|
@ -28,6 +28,14 @@ const schema = new Schema<IReview | any>(
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
beer_id: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
user_id: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
timestamps: true,
|
timestamps: true,
|
||||||
|
@ -1 +1 @@
|
|||||||
{"version":"2.0.0","endpoints":{"user":{"signup":{"name":"user","operation":"signup","route":"/api/v1/auth/signup","method":"POST","description":"user signup api","body":{"username":"testuser","email":"text@example.com","password":"Test1234"},"response":"status object"},"signin":{"name":"user","operation":"signin","route":"/api/v1/auth/signin","method":"POST","description":"user signin api","body":{"email":"text@example.com","password":"Test1234"},"response":"status object"},"logout":{"name":"user","operation":"logout","route":"/api/v1/auth/logout","method":"POST","description":"user logout api","body":{},"response":"status object"},"status":{"name":"user","operation":"status","route":"/api/v1/auth/status","method":"GET","description":"user login status api","response":"status code | user object"}},"beer":{"add":{"name":"beer","operation":"add","route":"/api/v1/beer/add","method":"POST","description":"beer add api","body":{"brand":"Pilsner Urqell","name":"Kozel","degree":11,"packaging":"can","photos":"optional field | max 4 images | formData"},"response":"status object | beer object"},"get":{"name":"beer","operation":"get","route":"/api/v1/beer/get","method":"GET","description":"beer get api","response":"status object | array of beer objects"},"del":{"name":"beer","operation":"del","route":"/api/v1/beer/del","method":"POST","description":"beer del api","body":{"_id":"6352b303b71cb62222f39895"},"response":"status object"},"edit":{"name":"beer","operation":"edit","route":"/api/v1/beer/edit","method":"POST","description":"beer edit api","body":{"_id":"6355b95dc03fad77bc380146","brand":"Pilsner Urqell","name":"Radegast","degree":12,"packaging":"bottle","imgs":[],"photos":"optional field | max 4 images | formData"},"response":"status object | beer data"}},"docs":{"get_all":{"name":"docs","operation":"get_all","route":"/api/v1","method":"GET","description":"Get docs json","response":"docs json"}}}}
|
{"version":"2.0.0","endpoints":{"user":{"signup":{"name":"user","operation":"signup","route":"/api/v1/auth/signup","method":"POST","description":"user signup api","body":{"username":"testuser","email":"text@example.com","password":"Test1234"},"response":"status object"},"signin":{"name":"user","operation":"signin","route":"/api/v1/auth/signin","method":"POST","description":"user signin api","body":{"email":"text@example.com","password":"Test1234"},"response":"status object"},"logout":{"name":"user","operation":"logout","route":"/api/v1/auth/logout","method":"POST","description":"user logout api","body":{},"response":"status object"},"status":{"name":"user","operation":"status","route":"/api/v1/auth/status","method":"GET","description":"user login status api","response":"status code | user object"}},"beer":{"add":{"name":"beer","operation":"add","route":"/api/v1/beer/add","method":"POST","description":"beer add api","body":{"brand":"Pilsner Urqell","name":"Kozel","degree":11,"packaging":"can","photos":"optional field | max 4 images | formData"},"response":"status object | beer object"},"get":{"name":"beer","operation":"get","route":"/api/v1/beer/get","method":"GET","description":"beer get api","response":"status object | array of beer objects"},"del":{"name":"beer","operation":"del","route":"/api/v1/beer/del","method":"POST","description":"beer del api","body":{"_id":"6352b303b71cb62222f39895"},"response":"status object"},"edit":{"name":"beer","operation":"edit","route":"/api/v1/beer/edit","method":"POST","description":"beer edit api","body":{"_id":"6355b95dc03fad77bc380146","brand":"Pilsner Urqell","name":"Radegast","degree":12,"packaging":"bottle","imgs":[],"photos":"optional field | max 4 images | formData"},"response":"status object | beer data"}},"docs":{"get_all":{"name":"docs","operation":"get_all","route":"/api/v1","method":"GET","description":"Get docs json","response":"docs json"}},"review":{"add":{"name":"review","operation":"add","route":"/api/v1/review/add","method":"POST","description":"review add api","body":{"beer_id":"6352b303b71cb62222f39895","foam":3,"bitter_sweetness":2,"taste":5,"packaging":3,"sourness":false,"would_again":true},"response":"status object | review object"},"get":{"name":"review","operation":"get","route":"/api/v1/review/get","method":"GET","description":"review get api","response":"status object | array of review objects"},"del":{"name":"review","operation":"del","route":"/api/v1/review/del","method":"POST","description":"review del api","body":{"_id":"6352b303b71cb62222f39895"},"response":"status object"}}}}
|
@ -20,6 +20,7 @@ export const add = yup.object({
|
|||||||
packaging: yup.number().min(1).max(5).required(),
|
packaging: yup.number().min(1).max(5).required(),
|
||||||
sourness: yup.boolean().required(),
|
sourness: yup.boolean().required(),
|
||||||
would_again: yup.boolean().required(),
|
would_again: yup.boolean().required(),
|
||||||
|
user_id: yup.string().notRequired()
|
||||||
});
|
});
|
||||||
export interface IReview extends yup.InferType<typeof add>, mongooseAddition {}
|
export interface IReview extends yup.InferType<typeof add>, mongooseAddition {}
|
||||||
export const addExam: IReview = {
|
export const addExam: IReview = {
|
||||||
|
1
frontend/.gitignore
vendored
@ -37,3 +37,4 @@ yarn-error.*
|
|||||||
.env
|
.env
|
||||||
|
|
||||||
.vscode/
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
@ -43,7 +43,7 @@ export default function TabLayout() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="review"
|
name="review/index"
|
||||||
options={{
|
options={{
|
||||||
title: "Reviews",
|
title: "Reviews",
|
||||||
tabBarIcon: ({ color }) => (
|
tabBarIcon: ({ color }) => (
|
||||||
@ -66,6 +66,10 @@ export default function TabLayout() {
|
|||||||
name="beer/add"
|
name="beer/add"
|
||||||
options={{ href: null, title: "Add beer" }}
|
options={{ href: null, title: "Add beer" }}
|
||||||
/>
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="review/add/[beer_id]"
|
||||||
|
options={{ href: null, title: "Add review" }}
|
||||||
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
@ -108,8 +108,12 @@ export default function BeerAdd() {
|
|||||||
|
|
||||||
async function addBeer() {
|
async function addBeer() {
|
||||||
// TODO: after the request - redirect to /beer/{new_beer_id}?; plus some modal about successful state
|
// TODO: after the request - redirect to /beer/{new_beer_id}?; plus some modal about successful state
|
||||||
|
|
||||||
const data = new FormData();
|
const data = new FormData();
|
||||||
|
if (Platform.OS == "web") {
|
||||||
|
// TODO: On phone its imposibble to upload an image
|
||||||
data.append("photos", dataURItoBlob(image.uri));
|
data.append("photos", dataURItoBlob(image.uri));
|
||||||
|
}
|
||||||
data.append("brand", b_brand);
|
data.append("brand", b_brand);
|
||||||
data.append("name", b_name);
|
data.append("name", b_name);
|
||||||
data.append("degree", b_degree);
|
data.append("degree", b_degree);
|
||||||
@ -124,7 +128,9 @@ export default function BeerAdd() {
|
|||||||
const res = await req.json();
|
const res = await req.json();
|
||||||
|
|
||||||
if (res.code == 201 && res.data._id) {
|
if (res.code == 201 && res.data._id) {
|
||||||
window.location.href = `/beer/${res.data._id}`;
|
// TODO: reditect using expo router
|
||||||
|
// window.location.href = `/beer/${res.data._id}`;
|
||||||
|
alert("Added");
|
||||||
} else {
|
} else {
|
||||||
alert(
|
alert(
|
||||||
"Beer was not added successfully. Please check your data and try again.",
|
"Beer was not added successfully. Please check your data and try again.",
|
||||||
@ -198,9 +204,8 @@ export default function BeerAdd() {
|
|||||||
) : (
|
) : (
|
||||||
false
|
false
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{image && <Image source={{ uri: image }} style={styles.image} />}
|
|
||||||
</View>
|
</View>
|
||||||
|
{image && <Image source={{ uri: image.uri }} style={styles.image} />}
|
||||||
<Button title="Add beer" color={colors.gold} onPress={addBeer} />
|
<Button title="Add beer" color={colors.gold} onPress={addBeer} />
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
@ -4,15 +4,17 @@ import {
|
|||||||
FlatList,
|
FlatList,
|
||||||
Dimensions,
|
Dimensions,
|
||||||
StatusBar,
|
StatusBar,
|
||||||
|
Image,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import Text from "@components/Text";
|
import Text from "@components/Text";
|
||||||
import Button from "@components/Button";
|
import Button from "@components/Button";
|
||||||
import { colors } from "@components/style";
|
import { colors } from "@components/style";
|
||||||
import { router } from "expo-router";
|
import { router } from "expo-router";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { FlashList } from "@shopify/flash-list";
|
// import { FlashList } from "@shopify/flash-list";
|
||||||
|
|
||||||
export default function Tab() {
|
export default function Tab() {
|
||||||
|
const API_HOST = process.env.EXPO_PUBLIC_API_URL.replace("/api/v1", "");
|
||||||
const [data, setData] = useState([]);
|
const [data, setData] = useState([]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchData();
|
fetchData();
|
||||||
@ -62,11 +64,34 @@ export default function Tab() {
|
|||||||
keyExtractor={(item) => String(item._id)}
|
keyExtractor={(item) => String(item._id)}
|
||||||
renderItem={({ item }) => (
|
renderItem={({ item }) => (
|
||||||
<View style={styles.item}>
|
<View style={styles.item}>
|
||||||
|
<Image
|
||||||
|
source={
|
||||||
|
item.imgs[0]
|
||||||
|
? {
|
||||||
|
uri: `${API_HOST}/public/uploads/${item.imgs[0]}`,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
uri: "https://imagesvc.meredithcorp.io/v3/mm/image?url=https:%2F%2Fstatic.onecms.io%2Fwp-content%2Fuploads%2Fsites%2F44%2F2020%2F09%2F29%2Flight-beer.jpg",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
style={styles.itemImg}
|
||||||
|
/>
|
||||||
|
<View style={styles.itemDesc}>
|
||||||
<Text>Name: {item.name}</Text>
|
<Text>Name: {item.name}</Text>
|
||||||
<Text>Brand: {item.brand}</Text>
|
<Text>Brand: {item.brand}</Text>
|
||||||
<Text>Degree: {item.degree}</Text>
|
<Text>Degree: {item.degree}</Text>
|
||||||
<Text>Packaging: {item.packaging}</Text>
|
<Text>Packaging: {item.packaging}</Text>
|
||||||
</View>
|
</View>
|
||||||
|
<View style={styles.itemAddReview}>
|
||||||
|
<Button
|
||||||
|
title="Add review"
|
||||||
|
color={colors.gold}
|
||||||
|
onPress={() => {
|
||||||
|
router.push(`/review/add/${item._id}`);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@ -92,4 +117,12 @@ export const styles = StyleSheet.create({
|
|||||||
padding: 13,
|
padding: 13,
|
||||||
marginBottom: "5%",
|
marginBottom: "5%",
|
||||||
},
|
},
|
||||||
|
itemImg: {
|
||||||
|
height: 300,
|
||||||
|
resizeMode: "contain",
|
||||||
|
},
|
||||||
|
itemDesc: {
|
||||||
|
alignItems: "center",
|
||||||
|
paddingBottom: "2%",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
import { View } from "react-native";
|
|
||||||
import Text from "@components/Text";
|
|
||||||
|
|
||||||
export default function Tab() {
|
|
||||||
return (
|
|
||||||
<View style={{ justifyContent: "center", alignItems: "center", flex: 1 }}>
|
|
||||||
<Text>Tab REVIEW</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
521
frontend/app/(app)/(tabs)/review/add/[beer_id].js
Normal file
@ -0,0 +1,521 @@
|
|||||||
|
import { StyleSheet, TextInput, View, Image } from "react-native";
|
||||||
|
import { useCallback, useState } from "react";
|
||||||
|
import Button from "@components/Button";
|
||||||
|
import Text from "@components/Text";
|
||||||
|
import { colors } from "@components/style";
|
||||||
|
import * as ImagePicker from "expo-image-picker";
|
||||||
|
import DropDownPicker from "react-native-dropdown-picker";
|
||||||
|
const DropdownTheme = require("@components/DropdownTheme");
|
||||||
|
import { Platform } from "react-native";
|
||||||
|
import { useLocalSearchParams } from "expo-router";
|
||||||
|
|
||||||
|
export default function reviewAdd() {
|
||||||
|
// States for each dropdown
|
||||||
|
const routeParams = useLocalSearchParams();
|
||||||
|
const [openFoam, setOpenFoam] = useState(false);
|
||||||
|
const [openBitterSweetness, setOpenBitterSweetness] = useState(false);
|
||||||
|
const [openTaste, setOpenTaste] = useState(false);
|
||||||
|
const [openPackaging, setOpenPackaging] = useState(false);
|
||||||
|
const [openSourness, setOpenSourness] = useState(false);
|
||||||
|
const [openAgain, setOpenAgain] = useState(false);
|
||||||
|
|
||||||
|
// pěna
|
||||||
|
const [itemFoam, setFoamValue] = useState(null);
|
||||||
|
const [foam, setFoam] = useState([
|
||||||
|
{
|
||||||
|
label: "Bad",
|
||||||
|
value: "1",
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley-x-eyes.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Medium",
|
||||||
|
value: "2",
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley-meh.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Excellent",
|
||||||
|
value: "3",
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// hořkost / sladkost
|
||||||
|
const [itemBitter_sweetness, setBitter_sweetnessValue] = useState(null);
|
||||||
|
const [bitter_sweetness, setBitter_sweetness] = useState([
|
||||||
|
{
|
||||||
|
label: "Bad",
|
||||||
|
value: "1",
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley-x-eyes.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Medium",
|
||||||
|
value: "2",
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley-meh.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Excellent",
|
||||||
|
value: "3",
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
//chuť
|
||||||
|
const [itemTaste, setTasteValue] = useState(null);
|
||||||
|
const [taste, setTaste] = useState([
|
||||||
|
{
|
||||||
|
label: "Disgust",
|
||||||
|
value: "1",
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley-blank.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Not great, not terrible",
|
||||||
|
value: "2",
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley-nervous.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Good",
|
||||||
|
value: "3",
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley-meh.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Why not",
|
||||||
|
value: "4",
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley-wink.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Excellent!",
|
||||||
|
value: "5",
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// packaging
|
||||||
|
const [itemPackaging, setPackagingValue] = useState(null);
|
||||||
|
const [packaging, setPackaging] = useState([
|
||||||
|
{
|
||||||
|
label: "Disgust",
|
||||||
|
value: "1",
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley-blank.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Not great, not terrible",
|
||||||
|
value: "2",
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley-nervous.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Good",
|
||||||
|
value: "3",
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley-meh.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Why not",
|
||||||
|
value: "4",
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley-wink.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Excellent!",
|
||||||
|
value: "5",
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
//kyselost
|
||||||
|
const [itemSourness, setSournessValue] = useState(null);
|
||||||
|
const [sourness, setSourness] = useState([
|
||||||
|
{
|
||||||
|
label: "True",
|
||||||
|
value: true,
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley-blank.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "False",
|
||||||
|
value: false,
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley-nervous.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
//dal bych si znovu?
|
||||||
|
const [itemAgain, setAgainValue] = useState(null);
|
||||||
|
const [again, setAgain] = useState([
|
||||||
|
{
|
||||||
|
label: "Yes",
|
||||||
|
value: true,
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "No",
|
||||||
|
value: false,
|
||||||
|
icon: () => (
|
||||||
|
<Image
|
||||||
|
source={require("@assets/smileys/smiley-x-eyes.png")}
|
||||||
|
style={styles.iconStyle}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
//podmínky pro zavření ostatních dropdownů, pokud je jiný otevřený
|
||||||
|
const onOpenFoam = useCallback(() => {
|
||||||
|
setOpenBitterSweetness(false);
|
||||||
|
setOpenTaste(false);
|
||||||
|
setOpenPackaging(false);
|
||||||
|
setOpenSourness(false);
|
||||||
|
setOpenAgain(false);
|
||||||
|
setOpenFoam(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onOpenBitterSweetness = useCallback(() => {
|
||||||
|
setOpenFoam(false);
|
||||||
|
setOpenTaste(false);
|
||||||
|
setOpenPackaging(false);
|
||||||
|
setOpenSourness(false);
|
||||||
|
setOpenAgain(false);
|
||||||
|
setOpenBitterSweetness(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onOpenTaste = useCallback(() => {
|
||||||
|
setOpenFoam(false);
|
||||||
|
setOpenBitterSweetness(false);
|
||||||
|
setOpenPackaging(false);
|
||||||
|
setOpenSourness(false);
|
||||||
|
setOpenAgain(false);
|
||||||
|
setOpenTaste(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onOpenPackaging = useCallback(() => {
|
||||||
|
setOpenFoam(false);
|
||||||
|
setOpenBitterSweetness(false);
|
||||||
|
setOpenTaste(false);
|
||||||
|
setOpenSourness(false);
|
||||||
|
setOpenAgain(false);
|
||||||
|
setOpenPackaging(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onOpenSourness = useCallback(() => {
|
||||||
|
setOpenFoam(false);
|
||||||
|
setOpenBitterSweetness(false);
|
||||||
|
setOpenTaste(false);
|
||||||
|
setOpenPackaging(false);
|
||||||
|
setOpenAgain(false);
|
||||||
|
setOpenSourness(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onOpenAgain = useCallback(() => {
|
||||||
|
setOpenFoam(false);
|
||||||
|
setOpenBitterSweetness(false);
|
||||||
|
setOpenTaste(false);
|
||||||
|
setOpenPackaging(false);
|
||||||
|
setOpenSourness(false);
|
||||||
|
setOpenAgain(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
DropDownPicker.addTheme("DropdownTheme", DropdownTheme);
|
||||||
|
DropDownPicker.setTheme("DropdownTheme");
|
||||||
|
|
||||||
|
async function addBeer() {
|
||||||
|
const req = await fetch(`${process.env.EXPO_PUBLIC_API_URL}/review/add`, {
|
||||||
|
method: "POST",
|
||||||
|
credentials: "include",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({
|
||||||
|
beer_id: routeParams.beer_id,
|
||||||
|
foam: itemFoam,
|
||||||
|
bitter_sweetness: itemBitter_sweetness,
|
||||||
|
taste: itemTaste,
|
||||||
|
packaging: itemPackaging,
|
||||||
|
sourness: itemSourness,
|
||||||
|
would_again: itemAgain,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
const res = await req.json();
|
||||||
|
|
||||||
|
if (res.code == 201 && res.data._id) {
|
||||||
|
// window.location.href = `/review/${res.data._id}`;
|
||||||
|
// TODO: use react router for redirect
|
||||||
|
alert("Review was added!");
|
||||||
|
} else {
|
||||||
|
alert(
|
||||||
|
"Review was not added successfully. Please check your data and try again.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<View style={styles.form}>
|
||||||
|
<Text style={styles.text}>
|
||||||
|
How does your beer taste? Write a review!
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.dropdownText} zIndex={6000} zIndexInverse={1000}>
|
||||||
|
How does the foam look like?
|
||||||
|
</Text>
|
||||||
|
<DropDownPicker
|
||||||
|
open={openFoam}
|
||||||
|
onOpen={onOpenFoam}
|
||||||
|
value={itemFoam}
|
||||||
|
items={foam}
|
||||||
|
setOpen={setOpenFoam}
|
||||||
|
setValue={setFoamValue}
|
||||||
|
setItems={setFoam}
|
||||||
|
placeholder="Please select..."
|
||||||
|
theme="DropdownTheme"
|
||||||
|
zIndex={6000}
|
||||||
|
zIndexInverse={1000}
|
||||||
|
/>
|
||||||
|
<Text style={styles.dropdownText} zIndex={5000} zIndexInverse={2000}>
|
||||||
|
More bitter, or more sweet?
|
||||||
|
</Text>
|
||||||
|
<DropDownPicker
|
||||||
|
open={openBitterSweetness}
|
||||||
|
onOpen={onOpenBitterSweetness}
|
||||||
|
value={itemBitter_sweetness}
|
||||||
|
items={bitter_sweetness}
|
||||||
|
setOpen={setOpenBitterSweetness}
|
||||||
|
setValue={setBitter_sweetnessValue}
|
||||||
|
setItems={setBitter_sweetness}
|
||||||
|
placeholder="Please select..."
|
||||||
|
theme="DropdownTheme"
|
||||||
|
zIndex={5000}
|
||||||
|
zIndexInverse={2000}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Text style={styles.dropdownText} zIndex={4000} zIndexInverse={3000}>
|
||||||
|
How does it taste?
|
||||||
|
</Text>
|
||||||
|
<DropDownPicker
|
||||||
|
open={openTaste}
|
||||||
|
onOpen={onOpenTaste}
|
||||||
|
value={itemTaste}
|
||||||
|
items={taste}
|
||||||
|
setOpen={setOpenTaste}
|
||||||
|
setValue={setTasteValue}
|
||||||
|
setItems={setTaste}
|
||||||
|
placeholder="Please select..."
|
||||||
|
theme="DropdownTheme"
|
||||||
|
zIndex={4000}
|
||||||
|
zIndexInverse={3000}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Text style={styles.dropdownText} zIndex={5000} zIndexInverse={4000}>
|
||||||
|
How do you like the packaging?
|
||||||
|
</Text>
|
||||||
|
<DropDownPicker
|
||||||
|
open={openPackaging}
|
||||||
|
onOpen={onOpenPackaging}
|
||||||
|
value={itemPackaging}
|
||||||
|
items={packaging}
|
||||||
|
setOpen={setOpenPackaging}
|
||||||
|
setValue={setPackagingValue}
|
||||||
|
setItems={setPackaging}
|
||||||
|
placeholder="Please select..."
|
||||||
|
theme="DropdownTheme"
|
||||||
|
zIndex={3000}
|
||||||
|
zIndexInverse={4000}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Text style={styles.dropdownText} zIndex={4000} zIndexInverse={5000}>
|
||||||
|
Is it sour?
|
||||||
|
</Text>
|
||||||
|
<DropDownPicker
|
||||||
|
open={openSourness}
|
||||||
|
onOpen={onOpenSourness}
|
||||||
|
value={itemSourness}
|
||||||
|
items={sourness}
|
||||||
|
setOpen={setOpenSourness}
|
||||||
|
setValue={setSournessValue}
|
||||||
|
setItems={setSourness}
|
||||||
|
placeholder="Please select..."
|
||||||
|
theme="DropdownTheme"
|
||||||
|
zIndex={2000}
|
||||||
|
zIndexInverse={5000}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Text style={styles.dropdownText} zIndex={5000} zIndexInverse={6000}>
|
||||||
|
Would you drink it again?
|
||||||
|
</Text>
|
||||||
|
<DropDownPicker
|
||||||
|
open={openAgain}
|
||||||
|
onOpen={onOpenAgain}
|
||||||
|
value={itemAgain}
|
||||||
|
items={again}
|
||||||
|
setOpen={setOpenAgain}
|
||||||
|
setValue={setAgainValue}
|
||||||
|
setItems={setAgain}
|
||||||
|
placeholder="Please select..."
|
||||||
|
theme="DropdownTheme"
|
||||||
|
zIndex={1000}
|
||||||
|
zIndexInverse={6000}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<View style={styles.buttonSend}>
|
||||||
|
<Button title="Add review" color={colors.gold} onPress={addBeer} />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
alignItems: "center",
|
||||||
|
display: "flex",
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
gap: 5,
|
||||||
|
width: "80%",
|
||||||
|
},
|
||||||
|
buttonSend: {
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
marginTop: "2%",
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
height: "auto",
|
||||||
|
width: "100%",
|
||||||
|
borderColor: "gray",
|
||||||
|
borderWidth: 1,
|
||||||
|
borderRadius: 10,
|
||||||
|
padding: 13,
|
||||||
|
color: "#fff",
|
||||||
|
},
|
||||||
|
imageContainer: {
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
gap: 10,
|
||||||
|
},
|
||||||
|
imageButton: {
|
||||||
|
backgroundColor: colors.dark,
|
||||||
|
borderColor: "gray",
|
||||||
|
borderWidth: 1,
|
||||||
|
borderRadius: 10,
|
||||||
|
},
|
||||||
|
imageTextButton: {
|
||||||
|
color: colors.white,
|
||||||
|
},
|
||||||
|
image: {
|
||||||
|
width: 150,
|
||||||
|
height: 150,
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
color: colors.white,
|
||||||
|
fontSize: 24,
|
||||||
|
textAlign: "center",
|
||||||
|
paddingBottom: "3%",
|
||||||
|
paddingTop: "10%",
|
||||||
|
},
|
||||||
|
iconStyle: {
|
||||||
|
width: 30,
|
||||||
|
height: 30,
|
||||||
|
},
|
||||||
|
dropdownContainer: {
|
||||||
|
width: "100%",
|
||||||
|
},
|
||||||
|
dropdownText: {
|
||||||
|
color: colors.white,
|
||||||
|
fontSize: 16,
|
||||||
|
paddingBottom: 1,
|
||||||
|
paddingTop: "1%",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "flex-start",
|
||||||
|
flexDirection: "column",
|
||||||
|
},
|
||||||
|
});
|
139
frontend/app/(app)/(tabs)/review/index.js
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
import { View, StyleSheet, FlatList, Image } from "react-native";
|
||||||
|
import Text from "@components/Text";
|
||||||
|
import Button from "@components/Button";
|
||||||
|
import { colors } from "@components/style";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { useAuth } from "@context/AuthContext";
|
||||||
|
|
||||||
|
export default function Tab() {
|
||||||
|
const { authState } = useAuth();
|
||||||
|
const user = authState.user;
|
||||||
|
const [data, setData] = useState([]);
|
||||||
|
useEffect(() => {
|
||||||
|
fetchData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const API_HOST = process.env.EXPO_PUBLIC_API_URL.replace("/api/v1", "");
|
||||||
|
|
||||||
|
async function fetchData() {
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${process.env.EXPO_PUBLIC_API_URL}/review/get`, {
|
||||||
|
method: "GET",
|
||||||
|
credentials: "include",
|
||||||
|
});
|
||||||
|
let data = await res.json();
|
||||||
|
// show only logged in user's data
|
||||||
|
data = data.data.filter((review) => review.user_id == user._id);
|
||||||
|
|
||||||
|
let beers = await fetch(`${process.env.EXPO_PUBLIC_API_URL}/beer/get`, {
|
||||||
|
method: "GET",
|
||||||
|
credentials: "include",
|
||||||
|
});
|
||||||
|
beers = await beers.json();
|
||||||
|
beers = beers.data;
|
||||||
|
console.log(beers);
|
||||||
|
|
||||||
|
async function getBeerParam(search, beers) {
|
||||||
|
for (let i = 0; i < beers.length; i++) {
|
||||||
|
if (beers[i]._id == search) {
|
||||||
|
return beers[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.forEach(async (el) => {
|
||||||
|
el.beer = await getBeerParam(el.beer_id, beers);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("reviews", data);
|
||||||
|
setData(data);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
alert("Something went wrong");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const opt3 = ["Bad", "Medium", "Excellent!"];
|
||||||
|
const opt5 = [
|
||||||
|
"Disgust",
|
||||||
|
"Not great, not terrible",
|
||||||
|
"Good",
|
||||||
|
"Why not?",
|
||||||
|
"Excellent!",
|
||||||
|
];
|
||||||
|
const opt2 = ["Yes", "No"];
|
||||||
|
const sourness = ["Good", "Bad"];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<FlatList
|
||||||
|
data={data}
|
||||||
|
style={styles.reviewList}
|
||||||
|
keyExtractor={(item) => String(item._id)}
|
||||||
|
renderItem={({ item }) => (
|
||||||
|
<View style={styles.itemContainer}>
|
||||||
|
<View>
|
||||||
|
<Text>{item.beer.name}</Text>
|
||||||
|
<Text>{item.beer.brand}</Text>
|
||||||
|
<Text>{item.beer.degree}°</Text>
|
||||||
|
<Text>{item.beer.packaging}</Text>
|
||||||
|
<Image
|
||||||
|
source={
|
||||||
|
item.beer.imgs[0]
|
||||||
|
? {
|
||||||
|
uri: `${API_HOST}/public/uploads/${item.beer.imgs[0]}`,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
uri: "https://imagesvc.meredithcorp.io/v3/mm/image?url=https:%2F%2Fstatic.onecms.io%2Fwp-content%2Fuploads%2Fsites%2F44%2F2020%2F09%2F29%2Flight-beer.jpg",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
style={styles.itemImg}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View>
|
||||||
|
<Text>Foam → {opt3[item.foam - 1]}</Text>
|
||||||
|
<Text>
|
||||||
|
Bitter / Sweetness → {opt3[item.bitter_sweetness - 1]}
|
||||||
|
</Text>
|
||||||
|
<Text>Taste → {opt5[item.taste - 1]}</Text>
|
||||||
|
<Text>Packaging → {opt5[item.packaging - 1]}</Text>
|
||||||
|
<Text>Sourness → {sourness[item.sourness - 1]}</Text>
|
||||||
|
<Text>Would again? → {opt2[item.would_again - 1]}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
marginTop: "5%",
|
||||||
|
},
|
||||||
|
reviewList: {
|
||||||
|
width: "100%",
|
||||||
|
paddingHorizontal: "15%",
|
||||||
|
marginTop: "5%",
|
||||||
|
},
|
||||||
|
itemContainer: {
|
||||||
|
borderColor: "gray",
|
||||||
|
borderWidth: 1,
|
||||||
|
borderRadius: 10,
|
||||||
|
padding: 13,
|
||||||
|
marginBottom: "5%",
|
||||||
|
flex: 1,
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
},
|
||||||
|
itemImg: {
|
||||||
|
width: 150,
|
||||||
|
aspectRatio: 1,
|
||||||
|
resizeMode: "contain",
|
||||||
|
marginTop: "5%",
|
||||||
|
},
|
||||||
|
});
|
BIN
frontend/assets/smileys/smiley-blank.png
Normal file
After Width: | Height: | Size: 7.9 KiB |
BIN
frontend/assets/smileys/smiley-meh.png
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
frontend/assets/smileys/smiley-nervous.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
frontend/assets/smileys/smiley-sad.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
frontend/assets/smileys/smiley-wink.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
frontend/assets/smileys/smiley-x-eyes.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
frontend/assets/smileys/smiley.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
205
frontend/package-lock.json
generated
@ -26,6 +26,7 @@
|
|||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-native": "0.74.1",
|
"react-native": "0.74.1",
|
||||||
"react-native-dropdown-picker": "^5.4.6",
|
"react-native-dropdown-picker": "^5.4.6",
|
||||||
|
"react-native-range-slider-expo": "^1.4.3",
|
||||||
"react-native-safe-area-context": "4.10.1",
|
"react-native-safe-area-context": "4.10.1",
|
||||||
"react-native-screens": "3.31.1",
|
"react-native-screens": "3.31.1",
|
||||||
"react-native-web": "~0.19.6"
|
"react-native-web": "~0.19.6"
|
||||||
@ -2257,6 +2258,18 @@
|
|||||||
"node": ">=14.21.3"
|
"node": ">=14.21.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@egjs/hammerjs": {
|
||||||
|
"version": "2.0.17",
|
||||||
|
"resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
|
||||||
|
"integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/hammerjs": "^2.0.36"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@expo/bunyan": {
|
"node_modules/@expo/bunyan": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@expo/bunyan/-/bunyan-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@expo/bunyan/-/bunyan-4.0.0.tgz",
|
||||||
@ -6367,6 +6380,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
||||||
"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="
|
"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/hammerjs": {
|
||||||
|
"version": "2.0.45",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.45.tgz",
|
||||||
|
"integrity": "sha512-qkcUlZmX6c4J8q45taBKTL3p+LbITgyx7qhlPYOdOHZB7B31K0mXbP5YA7i7SgDeEGuI9MnumiKPEMrxg8j3KQ==",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/@types/istanbul-lib-coverage": {
|
"node_modules/@types/istanbul-lib-coverage": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
|
||||||
@ -7008,6 +7027,12 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/boolbase": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/bplist-creator": {
|
"node_modules/bplist-creator": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz",
|
||||||
@ -7711,6 +7736,56 @@
|
|||||||
"hyphenate-style-name": "^1.0.3"
|
"hyphenate-style-name": "^1.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/css-select": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"boolbase": "^1.0.0",
|
||||||
|
"css-what": "^6.1.0",
|
||||||
|
"domhandler": "^5.0.2",
|
||||||
|
"domutils": "^3.0.1",
|
||||||
|
"nth-check": "^2.0.1"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/fb55"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/css-tree": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"mdn-data": "2.0.14",
|
||||||
|
"source-map": "^0.6.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/css-tree/node_modules/source-map": {
|
||||||
|
"version": "0.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
|
"peer": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/css-what": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
|
||||||
|
"integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
|
||||||
|
"peer": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/fb55"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/csstype": {
|
"node_modules/csstype": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||||
@ -7988,6 +8063,61 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dom-serializer": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": "^2.3.0",
|
||||||
|
"domhandler": "^5.0.2",
|
||||||
|
"entities": "^4.2.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/domelementtype": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/fb55"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
|
"node_modules/domhandler": {
|
||||||
|
"version": "5.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||||
|
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": "^2.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/domutils": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"dom-serializer": "^2.0.0",
|
||||||
|
"domelementtype": "^2.3.0",
|
||||||
|
"domhandler": "^5.0.3"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dotenv": {
|
"node_modules/dotenv": {
|
||||||
"version": "16.4.5",
|
"version": "16.4.5",
|
||||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
|
||||||
@ -8044,6 +8174,18 @@
|
|||||||
"once": "^1.4.0"
|
"once": "^1.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/entities": {
|
||||||
|
"version": "4.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||||
|
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||||
|
"peer": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/env-editor": {
|
"node_modules/env-editor": {
|
||||||
"version": "0.4.2",
|
"version": "0.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/env-editor/-/env-editor-0.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/env-editor/-/env-editor-0.4.2.tgz",
|
||||||
@ -9223,6 +9365,15 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/hoist-non-react-statics": {
|
||||||
|
"version": "3.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||||
|
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"react-is": "^16.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/hosted-git-info": {
|
"node_modules/hosted-git-info": {
|
||||||
"version": "3.0.8",
|
"version": "3.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz",
|
||||||
@ -11001,6 +11152,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/md5hex/-/md5hex-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/md5hex/-/md5hex-1.0.0.tgz",
|
||||||
"integrity": "sha512-c2YOUbp33+6thdCUi34xIyOU/a7bvGKj/3DB1iaPMTuPHf/Q2d5s4sn1FaCOO43XkXggnb08y5W2PU8UNYNLKQ=="
|
"integrity": "sha512-c2YOUbp33+6thdCUi34xIyOU/a7bvGKj/3DB1iaPMTuPHf/Q2d5s4sn1FaCOO43XkXggnb08y5W2PU8UNYNLKQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/mdn-data": {
|
||||||
|
"version": "2.0.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
|
||||||
|
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/memoize-one": {
|
"node_modules/memoize-one": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
|
||||||
@ -11866,6 +12023,18 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/nth-check": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"boolbase": "^1.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/nth-check?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/nullthrows": {
|
"node_modules/nullthrows": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz",
|
||||||
@ -12906,6 +13075,19 @@
|
|||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-native-gesture-handler": {
|
||||||
|
"version": "1.10.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-1.10.3.tgz",
|
||||||
|
"integrity": "sha512-cBGMi1IEsIVMgoox4RvMx7V2r6bNKw0uR1Mu1o7NbuHS6BRSVLq0dP34l2ecnPlC+jpWd3le6Yg1nrdCjby2Mw==",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@egjs/hammerjs": "^2.0.17",
|
||||||
|
"fbjs": "^3.0.0",
|
||||||
|
"hoist-non-react-statics": "^3.3.0",
|
||||||
|
"invariant": "^2.2.4",
|
||||||
|
"prop-types": "^15.7.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-native-helmet-async": {
|
"node_modules/react-native-helmet-async": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-helmet-async/-/react-native-helmet-async-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-helmet-async/-/react-native-helmet-async-2.0.4.tgz",
|
||||||
@ -12919,6 +13101,15 @@
|
|||||||
"react": "^16.6.0 || ^17.0.0 || ^18.0.0"
|
"react": "^16.6.0 || ^17.0.0 || ^18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-native-range-slider-expo": {
|
||||||
|
"version": "1.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-range-slider-expo/-/react-native-range-slider-expo-1.4.3.tgz",
|
||||||
|
"integrity": "sha512-EAIXfuCxJYffi6yqOcmCMWzvPNRSJ7zgDhQtVXXe2fokYaXVLG1uq2jM+cpTStMusIIGIo9HGZAja94N+rnNyg==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react-native-gesture-handler": "^1.6.1",
|
||||||
|
"react-native-svg": "^12.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-native-safe-area-context": {
|
"node_modules/react-native-safe-area-context": {
|
||||||
"version": "4.10.1",
|
"version": "4.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.10.1.tgz",
|
||||||
@ -12941,6 +13132,20 @@
|
|||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-native-svg": {
|
||||||
|
"version": "12.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-12.5.1.tgz",
|
||||||
|
"integrity": "sha512-c374ENsq2MWCfr+7jC7TGwSeOAuC1Dp0osh2pw8PjpYFxmmB/toFIwcnCLz+SgBd6iLJClRhbATealqM05HOGg==",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"css-select": "^5.1.0",
|
||||||
|
"css-tree": "^1.1.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "*",
|
||||||
|
"react-native": ">=0.50.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-native-web": {
|
"node_modules/react-native-web": {
|
||||||
"version": "0.19.11",
|
"version": "0.19.11",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.19.11.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.19.11.tgz",
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-native": "0.74.1",
|
"react-native": "0.74.1",
|
||||||
"react-native-dropdown-picker": "^5.4.6",
|
"react-native-dropdown-picker": "^5.4.6",
|
||||||
|
"react-native-range-slider-expo": "^1.4.3",
|
||||||
"react-native-safe-area-context": "4.10.1",
|
"react-native-safe-area-context": "4.10.1",
|
||||||
"react-native-screens": "3.31.1",
|
"react-native-screens": "3.31.1",
|
||||||
"react-native-web": "~0.19.6",
|
"react-native-web": "~0.19.6",
|
||||||
|