Changeset cc4db18
- Timestamp:
- 07/06/22 13:13:35 (2 years ago)
- Branches:
- master
- Children:
- 899b19d
- Parents:
- d76b7ee
- Files:
-
- 14 added
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
frontend/src/App.js
rd76b7ee rcc4db18 10 10 import Reservations from "./Dashboard/Reservations"; 11 11 import FrontPage from "./FrontPage"; 12 import Restaurant from "./Dashboard/Restaurant"; 13 import Menu from "./Dashboard/Menu"; 12 14 13 15 … … 32 34 <Routes> 33 35 <Route path="/dashboard" element={loading ? <Spin /> : user ?<Dashboard setUser={setUser}/> : <Navigate to="/login" replace={true} />}> 34 <Route path="/dashboard" element={ 'edit restaurant'}/>35 <Route path="/dashboard/menu" element={ 'menu'}/>36 <Route path="/dashboard" element={<Restaurant/>}/> 37 <Route path="/dashboard/menu" element={<Menu/>}/> 36 38 <Route path="/dashboard/reservations" element={<Reservations/>}/> 37 39 <Route path="/dashboard/reviews" element={'reviews'}/> -
frontend/src/Dashboard.js
rd76b7ee rcc4db18 28 28 to="/dashboard/reservations">Резервации</Link></Menu.Item> 29 29 <Menu.Item key="4" icon={<QuestionCircleOutlined/>}><Link 30 to="/dashboard/reviews"> Reviews</Link></Menu.Item>31 <Menu.Item key="5" icon={<BookOutlined/>}><Link to="/dashboard/todo">To do</Link></Menu.Item>30 to="/dashboard/reviews">Оценки</Link></Menu.Item> 31 <Menu.Item key="5" icon={<BookOutlined/>}><Link to="/dashboard/todo">ToDo</Link></Menu.Item> 32 32 </Menu> 33 33 </div> -
frontend/src/Dashboard/Reservations.js
rd76b7ee rcc4db18 1 1 import React, {useEffect, useState} from 'react' 2 import {Button, Modal, DatePicker, List, notification } from "antd";2 import {Button, Modal, DatePicker, List, notification, Input} from "antd"; 3 3 import AddNewReservation from "./AddNewReservation"; 4 4 import moment from 'moment' … … 13 13 const [date, setDate] = useState([moment().startOf('day'), moment().add(24,'hours')]); 14 14 const [reservations, setReservations] = useState([]) 15 const [newReservations, setNewReservations] = useState([]) 15 16 const [loadingReservations, setLoadingReservations] = useState(true) 16 17 … … 26 27 to: date[1].format('YYYY-MM-DDThh:mm:ss') + 'Z' 27 28 }, headers: {Authorization: sessionStorage.getItem('Auth')} 28 }) 29 .then(res => { 29 }).then(res => { 30 axios.get(env.api + 'Reservations/new', { 31 headers: {Authorization: sessionStorage.getItem('Auth')} 32 }).then(newres=>{ 33 setNewReservations(newres.data); 30 34 setReservations(res.data); 31 console.log(res.data)32 35 setLoadingReservations(false) 33 }).catch(er => { 36 }) 37 }).catch(er => { 34 38 setLoadingReservations(false) 35 39 notification['error']({ 36 40 message: 'Се случи проблем при додавање резервација. Ве молиме пробајте повторно подоцна', 37 41 }); 38 39 42 console.log(er); 40 43 }); … … 48 51 const changeReservationStatus = (id, newStatus) => { 49 52 console.log(id) 50 axios.put(env.api + 'Reservations/'+id ,{}, {53 axios.put(env.api + 'Reservations/'+id+'/status',{}, { 51 54 params: { 52 55 status: newStatus … … 59 62 }); 60 63 console.log(er); 61 }); 62 } 64 }) 65 } 66 const changeTable = (ev, item) => { 67 axios.put(env.api + 'Reservations/'+item.id+'/table',{}, { 68 params: { 69 tableId: ev.target.value == '' ? 0 : ev.target.value 70 }, headers: {Authorization: sessionStorage.getItem('Auth')} 71 }).then(res => { 72 console.log("success"); 73 }).catch(er => { 74 notification['error']({ 75 message: 'Се случи проблем при менување резервација. Ве молиме пробајте повторно подоцна', 76 }); 77 console.log(er); 78 }) 79 setNewReservations(old =>{ 80 const newRes = old.indexOf(item); 81 if(newRes == -1) return old; 82 const copy = [...old]; 83 copy[newRes].table = ev.target.value; 84 return copy; 85 }) 86 setReservations(old =>{ 87 const newRes = old.indexOf(item); 88 if(newRes == -1) return old; 89 const copy = [...old]; 90 copy[newRes].table = ev.target.value; 91 return copy; 92 }) 93 } 94 63 95 const ReservationType = [ 'Кратко', 'Долго', 'Настан' ]; 64 96 const ReservationPlace = [ 'Внатре', 'Надвор' ]; … … 84 116 border: '1px solid lightgray' 85 117 }} > 118 <h3 style={{float: 'left'}}>Нови резервации</h3> 119 </div> 120 <List loading={loadingReservations} dataSource={newReservations} itemLayout={'horizontal'} locale={{emptyText:'Немате нови резервации'}} 121 renderItem={item => ( 122 <List.Item 123 actions={ 124 item.reservationStatus == 0 ? 125 [<a onClick={()=>changeReservationStatus(item.id,ReservationStatus[1])}>Прифати</a>, <a style={{color:'red'}} onClick={()=>changeReservationStatus(item.id,ReservationStatus[2])}>Отфрли</a>] 126 : item.reservationStatus == 1 ? [<span style={{color:'green'}}>Прифатено</span>] : [<span style={{color:'red'}}>Отфрлено</span>]}> 127 <div style={{display:'flex',flexDirection:'row',justifyContent:'space-between',width:'100%', padding:'10px'}}> 128 <div style={{textAlign:'start', width:'200px'}}> 129 <div><b>Име:</b> {item.contactName}</div> 130 <div><b>Број:</b> {item.contactNumber}</div> 131 </div> 132 <div style={{marginTop:'10px'}}> 133 Маса: <Input style={{ width: '60px' }} type={'number'} value={item.table == 0 ? '' : item.table} onChange={(ev)=>changeTable(ev,item)}/> 134 </div> 135 <div> 136 <div><b>Луѓе:</b> {item.persons}</div> 137 <div>{ReservationPlace[item.reservationPlace]}, {ReservationType[item.reservationType]}</div> 138 </div> 139 <div> 140 <div style={{marginTop:'10px'}}>{moment(item.startDate).format('hh:mm DD/MM/YY')}</div> 141 </div> 142 </div> 143 </List.Item> 144 )}/> 145 </div> 146 <div style={{marginTop:'20px', backgroundColor:'white'}}> 147 <div style={{ 148 width: '100%', 149 height:'75px', 150 backgroundColor: 'white', 151 padding: '20px', 152 border: '1px solid lightgray' 153 }} > 86 154 <h3 style={{float: 'left'}}>Сите резервации</h3> 87 155 <RangePicker … … 89 157 style={{float:'right'}} 90 158 ranges={{ 159 'Наредни 3 часа': [moment(), moment().add(3,'hours')], 91 160 'Следни 24 часа': [moment().startOf('day'), moment().add(24,'hours')], 92 161 'Овој месец': [moment().startOf('month'), moment().endOf('month')], … … 96 165 /> 97 166 </div> 98 <List loading={loadingReservations} dataSource={reservations} itemLayout={'horizontal'} 167 <List loading={loadingReservations} dataSource={reservations} itemLayout={'horizontal'} locale={{emptyText:'Нема резервации за овој период'}} 99 168 renderItem={item => ( 100 169 <List.Item … … 107 176 <div><b>Име:</b> {item.contactName}</div> 108 177 <div><b>Број:</b> {item.contactNumber}</div> 178 </div> 179 <div style={{marginTop:'10px'}}> 180 Маса: <Input style={{ width: '60px' }} type={'number'} value={item.table == 0 ? '' : item.table} onChange={(ev)=>changeTable(ev,item)}/> 109 181 </div> 110 182 <div> -
frontend/src/FrontPage.js
rd76b7ee rcc4db18 1 import React, {useState } from 'react'1 import React, {useState, useEffect} from 'react' 2 2 import {Header} from "./Header"; 3 3 import {useNavigate} from "react-router-dom"; 4 import {Button, Image, Modal} from "antd";4 import {Button, Card, Image, Modal, Spin} from "antd"; 5 5 import placeholderImage from '../src/Assets/placeholder.png' 6 6 import AddNewReservation from "./Dashboard/AddNewReservation"; 7 import axios from "axios"; 8 import env from "./env"; 7 9 8 10 const FrontPage = ({}) => { … … 10 12 const [newReservationModal, setNewReservationModal] = useState(false); 11 13 const [saveModalLoading, setSaveModalLoading] = useState(false); 14 const [loading, setLoading] = useState(true); 12 15 const history = useNavigate(); 16 17 useEffect(()=>{ 18 setLoading(true); 19 axios.get(env.api + 'Restaurants').then(res=>{ 20 setRestaurant(res.data); 21 setLoading(false); 22 }); 23 },[]) 24 13 25 return( 14 26 <div> 15 27 <Header onClickButton={()=>history('/login')} buttonText={'Логирај се'}/> 28 {loading ? <Spin style={{margin: 20}}/> : 16 29 <div style={{ 17 30 height: '400px', … … 20 33 padding: '20px' 21 34 }}> 22 <div id={'businessFrontImage'}> 23 <Image 24 src={restaurant.photo} 25 id={'businessFrontInsideImage'} 26 placeholder={ 27 <img 28 src={placeholderImage} 29 alt={'place'} 30 style={{width:'100%',height:'100%'}} 31 /> 32 } 33 wrapperStyle={{overflow:'hidden',width:'100%'}} 34 style={{width:'100%', height:'100%',margin: 'auto',objectFit:'cover'}}> 35 </Image> 35 <div id={'businessFrontImage'}> 36 <Image 37 src={restaurant.base64Image} 38 id={'businessFrontInsideImage'} 39 placeholder={ 40 <img 41 src={placeholderImage} 42 alt={'place'} 43 style={{width: '100%', height: '100%'}} 44 /> 45 } 46 wrapperStyle={{overflow: 'hidden', width: '100%'}} 47 style={{width: '100%', height: '100%', margin: 'auto', objectFit: 'cover'}}> 48 </Image> 49 </div> 50 <div id={'businessFrontInfo'}> 51 <div style={{ 52 width: '100%', 53 height: '100%', 54 display: 'flex', 55 flexDirection: 'column', 56 justifyContent: 'space-between' 57 }}> 58 <div style={{flexGrow: 1, fontSize: '20px', fontWeight: '500', textAlign: 'start'}}> 59 {restaurant.name} 60 <div style={{ 61 color: 'gray', 62 fontSize: '10px' 63 }}>{restaurant.address}, {restaurant.phone}</div> 64 </div> 65 <Button onClick={() => setNewReservationModal(true)} 66 style={{width: '100%', marginTop: '5px'}} type={'primary'}>Резервирај</Button> 67 </div> 68 69 </div> 70 <div style={{textAlign: 'start', backgroundColor: '#F2F2F2'}}> 71 <h2 style={{textAlign:'center',paddingTop:'20px'}}>Мени</h2> 72 {restaurant.menu.map(el => 73 <Card title={el.title} style={{ width: 280, display:'inline-block', margin:'10px' }} size="small"> 74 <p>{el.description}</p> 75 <b>{el.price} ден.</b> 76 </Card> 77 )} 78 </div> 36 79 </div> 37 <div id={'businessFrontInfo'} > 38 <div style={{width:'100%',height:'100%',display:'flex',flexDirection:'column',justifyContent:'space-between'}}> 39 <div style={{flexGrow:1, fontSize:'20px', fontWeight:'500', textAlign:'start'}}> 40 {restaurant.name} 41 <div style={{color:'gray',fontSize:'10px'}}>{restaurant.address}, {restaurant.city}</div> 42 </div> 43 <Button onClick={()=>setNewReservationModal(true)} style={{width:'100%',marginTop:'5px'}} type={'primary'}>Резервирај</Button> 44 </div> 45 46 </div> 47 </div> 80 } 48 81 <Modal 49 82 style={{top: 20}} -
resTools_backend/backend/Controllers/ReservationsController.cs
rd76b7ee rcc4db18 27 27 } 28 28 29 [Authorize] 30 [HttpGet("new")] 31 public async Task<List<ReservationResponse>> GetReservationsNew() 32 { 33 return await _reservationService.GetNewReservations(); 34 } 35 29 36 [HttpPost()] 30 37 public async Task<IActionResult> CreateReservation([FromBody] CreateReservationRequest req) … … 35 42 36 43 [Authorize] 37 [HttpPut("{rid} ")]44 [HttpPut("{rid}/status")] 38 45 public async Task<IActionResult> ChangeStatus(int rid, [FromQuery] ReservationStatus status) 39 46 { … … 41 48 return Ok(); 42 49 } 50 51 [Authorize] 52 [HttpPut("{rid}/table")] 53 public async Task<IActionResult> ChangeTable(int rid, [FromQuery] int tableId) 54 { 55 await _reservationService.AssignTable(tableId, rid); 56 return Ok(); 57 } 43 58 } -
resTools_backend/backend/Controllers/RestaurantsController.cs
rd76b7ee rcc4db18 37 37 return response; 38 38 } 39 40 [HttpPost("upload")] 41 public async Task<IActionResult> UploadImage([FromForm] IFormFile file) 42 { 43 await _restaurantService.UploadImage(file); 44 return Ok(); 45 } 46 47 [Authorize] 48 [HttpPut()] 49 public async Task<IActionResult> UpdateRestaurant([FromBody] UpdateRestaurantRequest req) 50 { 51 await _restaurantService.UpdateRestaurant(req); 52 return Ok(); 53 } 39 54 } -
resTools_backend/backend/DTOs/ReservationResponse.cs
rd76b7ee rcc4db18 22 22 [JsonProperty] 23 23 public string ContactNumber { get; set; } 24 [JsonProperty] 25 public int Table { get; set; } 24 26 } 25 27 } -
resTools_backend/backend/DTOs/RestaurantResponse.cs
rd76b7ee rcc4db18 6 6 { 7 7 [JsonProperty] 8 public int Id{ get; set; }8 public string Name { get; set; } 9 9 [JsonProperty] 10 public int? OwnerId{ get; set; }10 public string Address { get; set; } 11 11 [JsonProperty] 12 public string Name { get; set; } 12 public string Phone { get; set; } 13 [JsonProperty] 14 public List<MenuItemResponse> Menu { get; set; } 15 [JsonProperty] 16 public string Base64Image { get; set; } 13 17 } 14 18 } -
resTools_backend/backend/Data/DataContext.cs
rd76b7ee rcc4db18 52 52 } 53 53 54 private DbSet<MenuItem> menuItems; 55 public DbSet<MenuItem> MenuItems 56 { 57 get 58 { 59 if (menuItems == null) 60 { 61 menuItems = Set<MenuItem>(); 62 } 63 64 return menuItems; 65 } 66 } 67 54 68 55 69 protected override void OnModelCreating(ModelBuilder modelBuilder) … … 74 88 .HasMany(p => p.Reservations) 75 89 .WithOne(b => b.Restaurant); 90 modelBuilder.Entity<Restaurant>() 91 .HasMany(p => p.Menu) 92 .WithOne(b => b.Restaurant); 93 76 94 77 95 // … … 82 100 .HasOne(p => p.Restaurant) 83 101 .WithMany(b => b.Reservations); 102 103 // 104 // MenuItem 105 // 106 modelBuilder.Entity<MenuItem>().Property(x => x.Id).IsRequired().ValueGeneratedOnAdd(); 107 modelBuilder.Entity<MenuItem>() 108 .HasOne(p => p.Restaurant) 109 .WithMany(b => b.Menu); 84 110 } 85 111 } -
resTools_backend/backend/Entities/Reservation.cs
rd76b7ee rcc4db18 14 14 public string ContactName { get; set; } 15 15 public string ContactNumber { get; set; } 16 public int Table { get; set; } 16 17 } 17 18 -
resTools_backend/backend/Entities/Restaurant.cs
rd76b7ee rcc4db18 9 9 public virtual User Owner { get; set; } 10 10 public virtual ICollection<Reservation> Reservations { get; set; } 11 public virtual ICollection<MenuItem> Menu { get; set; } 11 12 public string Name { get; set; } 13 public string Address { get; set; } 14 public string Phone { get; set; } 15 public byte[] Image { get; set; } 12 16 } 13 17 } -
resTools_backend/backend/Migrations/DataContextModelSnapshot.cs
rd76b7ee rcc4db18 23 23 NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); 24 24 25 modelBuilder.Entity("backend.Entities.MenuItem", b => 26 { 27 b.Property<int>("Id") 28 .ValueGeneratedOnAdd() 29 .HasColumnType("integer"); 30 31 NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); 32 33 b.Property<string>("Description") 34 .IsRequired() 35 .HasColumnType("text"); 36 37 b.Property<int>("Price") 38 .HasColumnType("integer"); 39 40 b.Property<int>("RestaurantId") 41 .HasColumnType("integer"); 42 43 b.Property<string>("Title") 44 .IsRequired() 45 .HasColumnType("text"); 46 47 b.HasKey("Id"); 48 49 b.HasIndex("RestaurantId"); 50 51 b.ToTable("MenuItems"); 52 }); 53 25 54 modelBuilder.Entity("backend.Entities.Reservation", b => 26 55 { … … 57 86 .HasColumnType("timestamp with time zone"); 58 87 88 b.Property<int>("Table") 89 .HasColumnType("integer"); 90 59 91 b.HasKey("Id"); 60 92 … … 72 104 NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); 73 105 106 b.Property<string>("Address") 107 .IsRequired() 108 .HasColumnType("text"); 109 110 b.Property<byte[]>("Image") 111 .IsRequired() 112 .HasColumnType("bytea"); 113 74 114 b.Property<string>("Name") 75 115 .IsRequired() … … 78 118 b.Property<int?>("OwnerFk") 79 119 .HasColumnType("integer"); 120 121 b.Property<string>("Phone") 122 .IsRequired() 123 .HasColumnType("text"); 80 124 81 125 b.HasKey("Id"); … … 106 150 107 151 b.ToTable("Users"); 152 }); 153 154 modelBuilder.Entity("backend.Entities.MenuItem", b => 155 { 156 b.HasOne("backend.Entities.Restaurant", "Restaurant") 157 .WithMany("Menu") 158 .HasForeignKey("RestaurantId") 159 .OnDelete(DeleteBehavior.Cascade) 160 .IsRequired(); 161 162 b.Navigation("Restaurant"); 108 163 }); 109 164 … … 130 185 modelBuilder.Entity("backend.Entities.Restaurant", b => 131 186 { 187 b.Navigation("Menu"); 188 132 189 b.Navigation("Reservations"); 133 190 }); -
resTools_backend/backend/Program.cs
rd76b7ee rcc4db18 46 46 builder.Services.AddScoped<IRestaurantService, RestaurantService>(); 47 47 builder.Services.AddScoped<IReservationService, ReservationService>(); 48 builder.Services.AddScoped<IMenuService, MenuService>(); 48 49 builder.Services.AddScoped<ISmsService, SmsService>(); 49 50 -
resTools_backend/backend/Services/ReservationService.cs
rd76b7ee rcc4db18 11 11 public Task ChangeReservationStatus(int resId, ReservationStatus status); 12 12 public Task<List<ReservationResponse>> GetReservatins(DateTime from, DateTime to); 13 public Task<List<ReservationResponse>> GetNewReservations(); 14 public Task AssignTable(int tableId, int reservationId); 13 15 } 14 16 public class ReservationService : IReservationService … … 21 23 _context = context; 22 24 _smsService = smsService; 25 } 26 27 public async Task AssignTable(int tableId, int reservationId) 28 { 29 var reservation = await _context.Reservations.FindAsync(reservationId); 30 reservation.Table = tableId; 31 _context.Update(reservation); 32 await _context.SaveChangesAsync(); 23 33 } 24 34 … … 50 60 } 51 61 62 public async Task<List<ReservationResponse>> GetNewReservations() 63 { 64 Restaurant res = await _context.Restoraunts 65 .Include(x => x.Reservations 66 .Where(x => x.ReservationStatus == ReservationStatus.New)) 67 .FirstOrDefaultAsync(); 68 var reservations = res.Reservations.Select(t => new ReservationResponse() 69 { 70 ContactName = t.ContactName, 71 ContactNumber = t.ContactNumber, 72 Persons = t.Persons, 73 StartDate = t.StartDate, 74 ReservationStatus = t.ReservationStatus, 75 Table = t.Table, 76 Id = t.Id, 77 ReservationPlace = t.ReservationPlace, 78 ReservationType = t.ReservationType 79 }).OrderByDescending(x => x.ReservationStatus == ReservationStatus.New).ToList(); 80 return reservations; 81 } 82 52 83 public async Task<List<ReservationResponse>> GetReservatins(DateTime from, DateTime to) 53 84 { … … 63 94 StartDate = t.StartDate, 64 95 ReservationStatus = t.ReservationStatus, 96 Table = t.Table, 65 97 Id = t.Id, 66 98 ReservationPlace = t.ReservationPlace, -
resTools_backend/backend/Services/RestaurantService.cs
rd76b7ee rcc4db18 10 10 public Task CreateRestaurant(string name, int userId); 11 11 public Task<RestaurantResponse> GetRestaurant(); 12 public Task UploadImage(IFormFile file); 13 public Task UpdateRestaurant(UpdateRestaurantRequest req); 12 14 } 13 15 public class RestaurantService : IRestaurantService … … 32 34 .Select(x => new RestaurantResponse() 33 35 { 34 Id = x.Id,35 36 Name = x.Name, 36 OwnerId = x.OwnerFk, 37 Address = x.Address, 38 Phone = x.Phone, 39 Base64Image = String.Format("data:image/png;base64,{0}", Convert.ToBase64String(x.Image)), 40 Menu = x.Menu.Select(x => new MenuItemResponse() 41 { 42 Id = x.Id, 43 Title = x.Title, 44 Description = x.Description, 45 Price = x.Price 46 }).ToList() 37 47 }) 38 48 .FirstOrDefaultAsync(); 39 49 return res; 40 50 } 51 52 public async Task UpdateRestaurant(UpdateRestaurantRequest req) 53 { 54 var restaurant = await _context.Restoraunts.FirstOrDefaultAsync(); 55 restaurant.Name = req.Name; 56 restaurant.Address = req.Address; 57 restaurant.Phone = req.Phone; 58 _context.Restoraunts.Update(restaurant); 59 await _context.SaveChangesAsync(); 60 } 61 62 public async Task UploadImage(IFormFile file) 63 { 64 using (var memoryStream = new MemoryStream()) 65 { 66 await file.CopyToAsync(memoryStream); 67 var restaurant = await _context.Restoraunts.FirstOrDefaultAsync(); 68 restaurant.Image = memoryStream.ToArray(); 69 _context.Restoraunts.Update(restaurant); 70 _context.SaveChanges(); 71 } 72 } 41 73 } 42 74 }
Note:
See TracChangeset
for help on using the changeset viewer.