Changeset 899b19d


Ignore:
Timestamp:
07/10/22 10:27:45 (2 years ago)
Author:
Danilo <danilo.najkov@…>
Branches:
master
Children:
a26f6a1
Parents:
cc4db18
Message:

reviews full feature

Files:
8 added
14 edited

Legend:

Unmodified
Added
Removed
  • frontend/src/App.js

    rcc4db18 r899b19d  
    11import './App.css';
    2 import {Route, BrowserRouter as Router, Navigate, Routes} from "react-router-dom";
     2import {Route, BrowserRouter as Router, Navigate, Routes, useNavigate} from "react-router-dom";
    33import axios from 'axios'
    44import env from './env'
     
    1212import Restaurant from "./Dashboard/Restaurant";
    1313import Menu from "./Dashboard/Menu";
     14import Review from "./Dashboard/Review";
    1415
    1516
    1617function App() {
    17   const [user, setUser] = useState(false)
     18  const [user, setUser] = useState(undefined)
    1819  const [loading, setLoading] = useState(false)
    1920  useEffect(()=>{
     
    2930    })
    3031  }
     32  const logout = () => {
     33    setUser(undefined);
     34    sessionStorage.removeItem('Auth');
     35    window.location.replace('/')
     36  }
    3137  return (
    3238    <div style={{textAlign:'center'}}>
    3339      <Router>
    3440          <Routes>
    35             <Route path="/dashboard" element={loading ? <Spin /> : user ?<Dashboard setUser={setUser}/> :  <Navigate to="/login" replace={true} />}>
     41            <Route path="/dashboard" element={loading ? <Spin /> : user ? (user.isAdmin ? <Dashboard setUser={setUser}/> : <Navigate to="/" replace={true} />) :  <Navigate to="/login" replace={true} />}>
    3642              <Route path="/dashboard" element={<Restaurant/>}/>
    3743              <Route path="/dashboard/menu" element={<Menu/>}/>
    3844              <Route path="/dashboard/reservations" element={<Reservations/>}/>
    39               <Route path="/dashboard/reviews" element={'reviews'}/>
     45              <Route path="/dashboard/reviews" element={<Review/>}/>
    4046              <Route path="/dashboard/todo" element={'todo'}/>
    4147            </Route>
    4248            <Route path="/login" element={loading ? <Spin /> :  !user ? <Login setUser={setUser}/> :  <Navigate to="/dashboard" replace={true} />}/>
    4349            <Route path="/register" element={loading ? <Spin /> :  !user ? <Register setUser={setUser}/> :  <Navigate to="/dashboard" replace={true} />}/>
    44             <Route path="/" element={<FrontPage/>}/>
     50            <Route path="/" element={<FrontPage user={user} logout={logout}/>}/>
    4551          </Routes>
    4652      </Router>
  • frontend/src/FrontPage.js

    rcc4db18 r899b19d  
    22import {Header} from "./Header";
    33import {useNavigate} from "react-router-dom";
    4 import {Button, Card, Image, Modal, Spin} from "antd";
     4import {Button, Card, DatePicker, Form, Image, Input, Modal, notification, Rate, Spin} from "antd";
    55import placeholderImage from '../src/Assets/placeholder.png'
    66import AddNewReservation from "./Dashboard/AddNewReservation";
    77import axios from "axios";
    88import env from "./env";
     9import Review from "./Dashboard/Review";
    910
    10 const FrontPage = ({}) => {
     11const FrontPage = ({user, logout}) => {
    1112    const [restaurant, setRestaurant] = useState({name:'Sample Restaurant name', address: 'Sample street 1', city:'Sample'});
    1213    const [newReservationModal, setNewReservationModal] = useState(false);
    1314    const [saveModalLoading, setSaveModalLoading] = useState(false);
     15    const [newReviewModal, setNewReviewModal] = useState(false);
    1416    const [loading, setLoading] = useState(true);
     17    const [refreshToggle, setRefreshToggle] = useState(false);
    1518    const history = useNavigate();
    1619
     
    2326    },[])
    2427
     28    const saveNewReview = data =>{
     29        setSaveModalLoading(true)
     30        axios.post(env.api + 'Reviews',data,{ headers: {Authorization: sessionStorage.getItem('Auth')}}).then(res=>{
     31            setNewReviewModal(false)
     32            setSaveModalLoading(false)
     33            notification['success']({
     34                message: 'Успешно зачувано',
     35            });
     36            setRefreshToggle(ref => !ref);
     37        }).catch(err=>{
     38            setSaveModalLoading(false)
     39            notification['error']({
     40                message: 'Се случи проблем при зачувување',
     41            });
     42        });
     43    }
     44
    2545    return(
    2646        <div>
    27             <Header onClickButton={()=>history('/login')} buttonText={'Логирај се'}/>
     47            <Header onClickButton={!user?()=>history('/login'):logout} buttonText={!user?'Најави се':'Одјави се'}/>
    2848            {loading ? <Spin style={{margin: 20}}/> :
    2949                <div style={{
     
    6989                    </div>
    7090                    <div style={{textAlign: 'start', backgroundColor: '#F2F2F2'}}>
    71                         <h2 style={{textAlign:'center',paddingTop:'20px'}}>Мени</h2>
     91                        <div style={{
     92                            width: '100%',
     93                            height:'75px',
     94                            backgroundColor: 'white',
     95                            padding: '20px',
     96                            border: '1px solid lightgray'
     97                        }} >
     98                            <h2 style={{float: 'left'}}>Мени</h2>
     99                        </div>
    72100                        {restaurant.menu.map(el =>
    73                             <Card title={el.title} style={{ width: 280, display:'inline-block', margin:'10px' }} size="small">
     101                            <Card key={el.id} title={el.title} style={{ width: 280, display:'inline-block', margin:'10px' }} size="small">
    74102                                <p>{el.description}</p>
    75103                                <b>{el.price} ден.</b>
    76104                            </Card>
    77105                        )}
     106                        <Review user={user} front refresh={refreshToggle} setVisible={setNewReviewModal}/>
    78107                    </div>
    79108                </div>
     
    92121                <AddNewReservation setModalSaveLoading={setSaveModalLoading} setModalVisible={setNewReservationModal} />
    93122            </Modal>
     123            <Modal
     124                style={{top: 20}}
     125                width={'700px'}
     126                title="Нова оценка"
     127                footer={[
     128                    <Button form="newReviewForm" key="submit" htmlType="submit" type={'primary'} loading={saveModalLoading}>
     129                        Прати
     130                    </Button>
     131                ]}
     132                onCancel={()=>setNewReviewModal(false)}
     133                visible={newReviewModal}>
     134                <Form onFinish={saveNewReview}
     135                      id={'newReviewForm'}
     136                      onFinishFailed={()=>
     137                          notification['error']({
     138                              message: 'Ве молиме поправете ги сите грешки пред зачувување!',
     139                          })}>
     140                    <Form.Item
     141                        label="Наслов"
     142                        name="title"
     143                        rules={[
     144                            {
     145                                required: true,
     146                                message: 'Ве молиме внесете наслов!',
     147                            },
     148                        ]}
     149                    >
     150                        <Input/>
     151                    </Form.Item>
     152                    <Form.Item
     153                        label="Опис"
     154                        name="description"
     155                        rules={[
     156                            {
     157                                required: true,
     158                                message: 'Ве молиме внесете опис!',
     159                            },
     160                        ]}
     161                    >
     162                        <Input.TextArea rows={4}/>
     163                    </Form.Item>
     164                    <Form.Item
     165                        label="Оценка"
     166                        name="stars"
     167                        rules={[
     168                            {
     169                                required: true,
     170                                message: 'Ве молиме внесете оценка!',
     171                            },
     172                        ]}
     173                    >
     174                        <Rate/>
     175                    </Form.Item>
     176                </Form>
     177            </Modal>
    94178        </div>
    95 
    96179    )
    97180}
    98 
    99181export default FrontPage;
  • frontend/src/auth.js

    rcc4db18 r899b19d  
    2121            setAuthCookie(res.data.token)
    2222            console.log(res.data.token)
    23             setUser(true)
     23            setUser(res.data)
    2424            setLoading(false)
    25             history('/dashboard')
     25            history(res.data.isAdmin ? '/dashboard' : '/')
    2626        }).catch(el => {
    2727            Modal.error({
     
    101101        axios.post(env.api+'Users/register',{email: attr.email, password: attr.password}).then(res => {
    102102            setAuthCookie(res.data.token)
    103             setUser(true)
     103            setUser(res.data)
    104104            setLoading(false)
    105             history('/dashboard')
     105            history(res.data.isAdmin ? '/dashboard' : '/')
    106106        })
    107107    }
  • resTools_backend/backend/Controllers/RestaurantsController.cs

    rcc4db18 r899b19d  
    2020    }
    2121
     22    /*
    2223    [Authorize]
    2324    [HttpPost()]
     
    3031        return Ok();
    3132    }
     33    */
    3234
    3335    [HttpGet()]
  • resTools_backend/backend/Controllers/UsersController.cs

    rcc4db18 r899b19d  
    1313{
    1414    private readonly IUserService _userService = null;
     15    private readonly IRestaurantService _restaurantService = null;
    1516
    16     public UsersController(IUserService userService)
     17    public UsersController(IUserService userService, IRestaurantService restaurantService)
    1718    {
    1819        _userService = userService;
     20        _restaurantService = restaurantService;
    1921    }
    2022
     
    4547    public async Task<AuthenticateResponse> Register(CreateUserRequest req)
    4648    {
    47         var response = await _userService.Register(req);
     49        bool isFirst = await _restaurantService.GetRestaurant() == null;
     50        var response = await _userService.Register(req, isFirst);
     51        if (isFirst)
     52        {
     53            await _restaurantService.CreateRestaurant("", response.Id);
     54        }
    4855        return response;
    4956    }
  • resTools_backend/backend/DTOs/AuthenticateResponse.cs

    rcc4db18 r899b19d  
    1313    [JsonProperty]
    1414    public string Token { get; set; }
     15    [JsonProperty]
     16    public bool IsAdmin { get; set; }
    1517}
  • resTools_backend/backend/DTOs/RestaurantResponse.cs

    rcc4db18 r899b19d  
    1414        public List<MenuItemResponse> Menu { get; set; }
    1515        [JsonProperty]
     16        public List<ReviewResponse> Reviews { get; set; }
     17        [JsonProperty]
     18        public double AverageReview { get; set; }
     19        [JsonProperty]
    1620        public string Base64Image { get; set; }
    1721    }
  • resTools_backend/backend/Data/DataContext.cs

    rcc4db18 r899b19d  
    6666        }
    6767
     68        private DbSet<Review> reviews;
     69        public DbSet<Review> Reviews
     70        {
     71            get
     72            {
     73                if (reviews == null)
     74                {
     75                    reviews = Set<Review>();
     76                }
     77
     78                return reviews;
     79            }
     80        }
     81
    6882
    6983        protected override void OnModelCreating(ModelBuilder modelBuilder)
     
    89103            .WithOne(b => b.Restaurant);
    90104            modelBuilder.Entity<Restaurant>()
    91             .HasMany(p => p.Menu)
     105            .HasMany(p => p.Reviews)
    92106            .WithOne(b => b.Restaurant);
    93 
    94107
    95108            //
     
    108121            .HasOne(p => p.Restaurant)
    109122            .WithMany(b => b.Menu);
     123
     124            //
     125            // Review
     126            //
     127            modelBuilder.Entity<Review>().Property(x => x.Id).IsRequired().ValueGeneratedOnAdd();
     128            modelBuilder.Entity<Review>()
     129            .HasOne(p => p.Restaurant)
     130            .WithMany(b => b.Reviews);
     131            modelBuilder.Entity<Review>()
     132            .HasOne(p => p.User);
    110133        }
    111134    }
  • resTools_backend/backend/Entities/Restaurant.cs

    rcc4db18 r899b19d  
    1010        public virtual ICollection<Reservation> Reservations { get; set; }
    1111        public virtual ICollection<MenuItem> Menu { get; set; }
     12        public virtual ICollection<Review> Reviews { get; set; }
    1213        public string Name { get; set; }
    1314        public string Address { get; set; }
  • resTools_backend/backend/Entities/User.cs

    rcc4db18 r899b19d  
    88    public string Email { get; set; }
    99    public string Password { get; set; }
    10     [JsonIgnore]
     10    public bool IsAdmin { get; set; }
    1111    public virtual Restaurant Restaurant { get; set; }
    1212}
  • resTools_backend/backend/Migrations/DataContextModelSnapshot.cs

    rcc4db18 r899b19d  
    131131                });
    132132
     133            modelBuilder.Entity("backend.Entities.Review", b =>
     134                {
     135                    b.Property<int>("Id")
     136                        .ValueGeneratedOnAdd()
     137                        .HasColumnType("integer");
     138
     139                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
     140
     141                    b.Property<DateTime>("CreatedAt")
     142                        .HasColumnType("timestamp with time zone");
     143
     144                    b.Property<string>("Description")
     145                        .IsRequired()
     146                        .HasColumnType("text");
     147
     148                    b.Property<int>("RestaurantId")
     149                        .HasColumnType("integer");
     150
     151                    b.Property<int>("Stars")
     152                        .HasColumnType("integer");
     153
     154                    b.Property<string>("Title")
     155                        .IsRequired()
     156                        .HasColumnType("text");
     157
     158                    b.Property<int>("UserId")
     159                        .HasColumnType("integer");
     160
     161                    b.HasKey("Id");
     162
     163                    b.HasIndex("RestaurantId");
     164
     165                    b.HasIndex("UserId");
     166
     167                    b.ToTable("Reviews");
     168                });
     169
    133170            modelBuilder.Entity("backend.Entities.User", b =>
    134171                {
     
    142179                        .IsRequired()
    143180                        .HasColumnType("text");
     181
     182                    b.Property<bool>("IsAdmin")
     183                        .HasColumnType("boolean");
    144184
    145185                    b.Property<string>("Password")
     
    183223                });
    184224
     225            modelBuilder.Entity("backend.Entities.Review", b =>
     226                {
     227                    b.HasOne("backend.Entities.Restaurant", "Restaurant")
     228                        .WithMany("Reviews")
     229                        .HasForeignKey("RestaurantId")
     230                        .OnDelete(DeleteBehavior.Cascade)
     231                        .IsRequired();
     232
     233                    b.HasOne("backend.Entities.User", "User")
     234                        .WithMany()
     235                        .HasForeignKey("UserId")
     236                        .OnDelete(DeleteBehavior.Cascade)
     237                        .IsRequired();
     238
     239                    b.Navigation("Restaurant");
     240
     241                    b.Navigation("User");
     242                });
     243
    185244            modelBuilder.Entity("backend.Entities.Restaurant", b =>
    186245                {
     
    188247
    189248                    b.Navigation("Reservations");
     249
     250                    b.Navigation("Reviews");
    190251                });
    191252
  • resTools_backend/backend/Program.cs

    rcc4db18 r899b19d  
    4747builder.Services.AddScoped<IReservationService, ReservationService>();
    4848builder.Services.AddScoped<IMenuService, MenuService>();
     49builder.Services.AddScoped<IReviewService, ReviewService>();
    4950builder.Services.AddScoped<ISmsService, SmsService>();
    5051
  • resTools_backend/backend/Services/RestaurantService.cs

    rcc4db18 r899b19d  
    3232        {
    3333            RestaurantResponse res = await _context.Restoraunts
     34                .Include(x => x.Menu)
     35                .Include(x => x.Reviews).ThenInclude(x => x.User)
    3436                .Select(x => new RestaurantResponse()
    3537                {
     
    4446                        Description = x.Description,
    4547                        Price = x.Price
    46                     }).ToList()
     48                    }).ToList(),
     49                    Reviews = x.Reviews.OrderByDescending(x => x.CreatedAt).Select(x => new ReviewResponse()
     50                    {
     51                        Id = x.Id,
     52                        Title = x.Title,
     53                        Description = x.Description,
     54                        Stars = x.Stars,
     55                        CreatedAt = x.CreatedAt,
     56                        Username = x.User == null ? "Anonymous" : x.User.Email
     57                    }).ToList(),
     58                    AverageReview = x.Reviews.Count>0 ? x.Reviews.Select(x => x.Stars).Average() : 0
    4759                })
    4860                .FirstOrDefaultAsync();
  • resTools_backend/backend/Services/UserService.cs

    rcc4db18 r899b19d  
    1515{
    1616    Task<AuthenticateResponse> Authenticate(AuthenticateRequest model);
    17     Task<AuthenticateResponse> Register(CreateUserRequest req);
     17    Task<AuthenticateResponse> Register(CreateUserRequest req, bool isFirst);
    1818    Task<User> GetById(int id);
    1919}
     
    4040        var token = generateJwtToken(user);
    4141
    42         return new AuthenticateResponse { Email = user.Email, Id = user.Id, Token = token};
     42        return new AuthenticateResponse { Email = user.Email, Id = user.Id, Token = token, IsAdmin = user.IsAdmin};
    4343    }
    4444
     
    4848    }
    4949
    50     public async Task<AuthenticateResponse> Register(CreateUserRequest req)
     50    public async Task<AuthenticateResponse> Register(CreateUserRequest req, bool isFirst)
    5151    {
    52         User user = new User() { Email = req.Email, Password = req.Password };
     52        User user = new User() { Email = req.Email, Password = req.Password, IsAdmin = isFirst };
    5353        await _context.Users.AddAsync(user);
    5454        await _context.SaveChangesAsync();
    5555        var token = generateJwtToken(user);
    56         return new AuthenticateResponse { Email = user.Email, Id = user.Id, Token = token };
     56        return new AuthenticateResponse { Email = user.Email, Id = user.Id, Token = token, IsAdmin = user.IsAdmin };
    5757    }
    5858
Note: See TracChangeset for help on using the changeset viewer.