Home.jsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import React, { useState, useEffect } from 'react';
  2. import { Container, Typography, TextField, Button, Box, Grid, Card, CardContent, CardMedia, Rating, IconButton } from '@mui/material';
  3. import MyLocationIcon from '@mui/icons-material/MyLocation';
  4. import SearchIcon from '@mui/icons-material/Search';
  5. const Home = () => {
  6. const [restaurants, setRestaurants] = useState([]);
  7. const [location, setLocation] = useState(null);
  8. const [searchQuery, setSearchQuery] = useState('');
  9. useEffect(() => {
  10. fetchRestaurants();
  11. }, []);
  12. const fetchRestaurants = async (lat, lng) => {
  13. let url = '/restaurants';
  14. if (lat && lng) {
  15. url += `?lat=${lat}&lng=${lng}`;
  16. }
  17. try {
  18. const response = await fetch(url);
  19. if (response.ok) {
  20. const data = await response.json();
  21. setRestaurants(data);
  22. }
  23. } catch (error) {
  24. console.error('Error fetching restaurants:', error);
  25. }
  26. };
  27. const handleUseCurrentLocation = () => {
  28. if (navigator.geolocation) {
  29. navigator.geolocation.getCurrentPosition(
  30. (position) => {
  31. const { latitude, longitude } = position.coords;
  32. setLocation({ latitude, longitude });
  33. fetchRestaurants(latitude, longitude);
  34. },
  35. (error) => {
  36. console.error('Error getting location:', error);
  37. }
  38. );
  39. } else {
  40. alert('Geolocation is not supported by this browser.');
  41. }
  42. };
  43. const handleSearch = () => {
  44. if (!searchQuery) {
  45. fetchRestaurants(location?.latitude, location?.longitude);
  46. return;
  47. }
  48. const filtered = restaurants.filter(r => r.name.toLowerCase().includes(searchQuery.toLowerCase()));
  49. setRestaurants(filtered);
  50. };
  51. return (
  52. <Container maxWidth="xl">
  53. <Box sx={{ my: 4, textAlign: 'center' }}>
  54. <Typography variant="h3" component="h1" gutterBottom>
  55. Find the Best Lunch Deals Near You
  56. </Typography>
  57. <Typography variant="h6" color="text.secondary" paragraph>
  58. Discover restaurants with amazing lunch specials shared by the community.
  59. </Typography>
  60. <Box sx={{ display: 'flex', justifyContent: 'center', mt: 4, mb: 6 }}>
  61. <TextField
  62. label="Search restaurants or location"
  63. variant="outlined"
  64. size="medium"
  65. sx={{ width: '50%', mr: 1 }}
  66. value={searchQuery}
  67. onChange={(e) => setSearchQuery(e.target.value)}
  68. />
  69. <Button variant="contained" size="large" onClick={handleSearch} startIcon={<SearchIcon />}>
  70. Search
  71. </Button>
  72. <IconButton color="primary" sx={{ ml: 1 }} onClick={handleUseCurrentLocation} title="Use Current Location">
  73. <MyLocationIcon />
  74. </IconButton>
  75. </Box>
  76. </Box>
  77. <Grid container spacing={4}>
  78. {restaurants.map((restaurant) => (
  79. <Grid item key={restaurant.id} xs={12} sm={6} md={4}>
  80. <Card sx={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
  81. <CardMedia
  82. component="img"
  83. height="200"
  84. image={restaurant.images[0] || 'https://via.placeholder.com/300x200?text=No+Image'}
  85. alt={restaurant.name}
  86. />
  87. <CardContent sx={{ flexGrow: 1 }}>
  88. <Typography gutterBottom variant="h5" component="h2">
  89. {restaurant.name}
  90. </Typography>
  91. <Typography variant="body2" color="text.secondary" gutterBottom>
  92. {restaurant.address}
  93. </Typography>
  94. <Box sx={{ display: 'flex', alignItems: 'center', mb: 1 }}>
  95. <Rating value={restaurant.user_rating} readOnly precision={0.5} size="small" />
  96. <Typography variant="body2" color="text.secondary" sx={{ ml: 1 }}>
  97. ({restaurant.user_rating}/10)
  98. </Typography>
  99. </Box>
  100. <Typography variant="h6" color="primary">
  101. ${restaurant.min_price} - ${restaurant.max_price}
  102. </Typography>
  103. </CardContent>
  104. </Card>
  105. </Grid>
  106. ))}
  107. </Grid>
  108. </Container>
  109. );
  110. };
  111. export default Home;