Changeset f29cd58
- Timestamp:
- 01/15/24 00:11:01 (10 months ago)
- Branches:
- master
- Children:
- 943857c
- Parents:
- e8999eb
- Location:
- src/main
- Files:
-
- 2 added
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
src/main/java/edu/gjoko/schedlr/controllers/rest/ServiceApi.java
re8999eb rf29cd58 1 1 package edu.gjoko.schedlr.controllers.rest; 2 2 3 import edu.gjoko.schedlr.dto.ServiceDto; 3 4 import edu.gjoko.schedlr.entity.Service; 5 import edu.gjoko.schedlr.mappers.ServiceDtoMapper; 4 6 import edu.gjoko.schedlr.services.ServicesService; 5 7 import lombok.AllArgsConstructor; … … 18 20 19 21 private ServicesService service; 22 private ServiceDtoMapper serviceDtoMapper; 20 23 @PostMapping(path="/delete") 21 24 public void saveBusiness(@RequestBody List<Service> serviceList) { … … 34 37 service.saveOrUpdateServices(serviceList, ownerId); 35 38 } 39 40 @GetMapping 41 public List<ServiceDto> searchServicesByKeyWord(@RequestParam(value = "searchKeyword", required = false) String searchKeyWord) { 42 return service.getServicesByKeyword(searchKeyWord) 43 .stream() 44 .map(serviceDtoMapper::serviceToServiceDto) 45 .toList(); 46 } 36 47 } -
src/main/java/edu/gjoko/schedlr/entity/Service.java
re8999eb rf29cd58 50 50 private Business business; 51 51 52 @Column(name = "description") 53 private String description; 54 52 55 @OneToMany(mappedBy="service") 53 56 @JsonManagedReference(value = "serviceAppointments") -
src/main/java/edu/gjoko/schedlr/repositories/ServiceRepository.java
re8999eb rf29cd58 11 11 @Repository 12 12 public interface ServiceRepository extends JpaRepository<Service, Long> { 13 14 @Query(value = "select s from Service as s " + 15 " where (s.serviceType.name like CONCAT('%', :keyword, '%') " + 16 " or s.description like CONCAT('%', :keyword, '%'))" + 17 " and s.serviceStatus = 'ACTIVE'") 18 List<Service> getServicesByKeyword(String keyword); 13 19 } -
src/main/java/edu/gjoko/schedlr/services/ServicesService.java
re8999eb rf29cd58 5 5 import edu.gjoko.schedlr.entity.ServiceType; 6 6 import edu.gjoko.schedlr.repositories.BusinessRepository; 7 import edu.gjoko.schedlr.repositories.BusinessTypeRepository;8 7 import edu.gjoko.schedlr.repositories.ServiceRepository; 9 8 import edu.gjoko.schedlr.repositories.ServiceTypeRepository; … … 29 28 } 30 29 30 public List<edu.gjoko.schedlr.entity.Service> getServicesByKeyword(String keyword) { 31 return serviceRepository.getServicesByKeyword(keyword); 32 } 33 31 34 public void saveOrUpdateServices(List<edu.gjoko.schedlr.entity.Service> serviceList, Long ownerId) { 32 35 if (!CollectionUtils.isEmpty(serviceList)) { … … 38 41 found.setPrice(service.getPrice()); 39 42 found.setServiceStatus(ServiceStatus.ACTIVE); 43 found.setDescription(service.getDescription()); 40 44 serviceRepository.save(found); 41 45 } else { -
src/main/resources/data.sql
re8999eb rf29cd58 29 29 (40001, 'ACTIVE', 'Manikir Marija', current_timestamp, current_timestamp, 2, 40000); 30 30 31 insert into service (id, created, modified, service_status, duration, price, cumulated_rating, reviews_count, business_id, service_type_id )32 values (10002, current_timestamp, current_timestamp, 'ACTIVE', 60, 400, 0, 0, 10001, 6 ),33 (10003, current_timestamp, current_timestamp, 'ACTIVE', 30, 200, 0, 0, 10001, 7 ),34 (40002, current_timestamp, current_timestamp, 'ACTIVE', 60, 600, 0, 0, 40001, 5 );31 insert into service (id, created, modified, service_status, duration, price, cumulated_rating, reviews_count, business_id, service_type_id, description) 32 values (10002, current_timestamp, current_timestamp, 'ACTIVE', 60, 400, 0, 0, 10001, 6, 'Sewing dress with previously bought material.'), 33 (10003, current_timestamp, current_timestamp, 'ACTIVE', 30, 200, 0, 0, 10001, 7, 'Shortening of pants and fixing pant''s edges.'), 34 (40002, current_timestamp, current_timestamp, 'ACTIVE', 60, 600, 0, 0, 40001, 5, 'Removing old nail extensions and creating new ones.'); 35 35 36 36 insert into appointment (id, created, modified, start_time, end_time, stakeholder_id, service_id) -
src/main/resources/static/css/homepage.css
re8999eb rf29cd58 75 75 padding: 10px; 76 76 } 77 78 .welcome_message { 79 width:480px; 80 margin:auto; 81 } -
src/main/resources/static/js/business_admin.js
re8999eb rf29cd58 35 35 ' </div>' + 36 36 ' </div>' + 37 ' <div class="row" style="margin-top:10px;">' + 38 ' <div class="form-outline col-md-10 d-grid">' + 39 ' <input type="text" id="' + -1 + input_service.replace(/\s/g, "") + "description" + '" class="form-control" placeholder="description" />' + 40 ' </div>' + 41 ' </div>' + 37 42 '</div>'); 38 43 event.preventDefault(); … … 49 54 var time = $($($(label).parent()).siblings()[0]).children()[0].value; 50 55 var price = $($($(label).parent()).siblings()[1]).children()[0].value; 56 var description = $($($($($($(label).parent())).parent()).siblings()[0]).children()[0]).children()[0].value; 51 57 52 58 var serviceType = {}; … … 61 67 service['duration'] = parseInt(time); 62 68 service['price'] = parseInt(price); 69 service['description'] = description; 63 70 servicesObj.push(service); 64 71 }); … … 251 258 $.each(business['services'], function (index, obj) { 252 259 253 var element = '<div class=\"form-outline mb-4\">' + 260 var element = 261 '<div class=\"form-outline mb-4\">' + 254 262 ' <div class="row">' + 255 263 ' <div class="col-md-6">\n' + … … 270 278 ' </div>' + 271 279 ' </div>' + 280 ' <div class="row" style="margin-top:10px;">' + 281 ' <div class="form-outline col-md-10 d-grid">' + 282 ' <input type="text" id="' + obj.id + obj['serviceType'].name.replace(/\s/g, "") + "description" + '" class="form-control" placeholder="description" value=\"' + obj.description + '" />' + 283 ' </div>' + 284 ' </div>' + 272 285 '</div>'; 273 286 -
src/main/resources/static/js/homepage.js
re8999eb rf29cd58 94 94 }); 95 95 96 $("#company").change(function () {97 resetRatingCard();98 var selectedVal = $(this).find(':selected').val();99 $.ajax({100 url: "http://localhost:8080/api/appointment/business/" + selectedVal101 }).then(function (data) {102 // get already stored service from in-memory103 selectedServices = businesses.find(item => item.id == selectedVal)['services'];104 console.log(selectedServices);105 resetAndAppendServices(selectedServices);106 });107 $('#calendar').fullCalendar('refetchEvents');108 });109 110 $("#service").change(function () {111 var selectedVal = $("#service").find(':selected').val();112 var service = selectedServices.find(item => item.id == selectedVal);113 setRatingCard(service['serviceType']['name'], service['rating'], service['reviewsCount'], selectedVal);114 });115 116 96 $("#startdatetime").change(function() { 117 97 var date = new Date(document.getElementById("startdatetime").valueAsDate); 118 var selectedVal = $("#service").find(':selected').val(); 119 var minutes = selectedServices.find(item => item.id == selectedVal)['duration']; 98 var minutes = parseInt($("#service").attr('duration')); 120 99 date.setMinutes(date.getMinutes() + minutes); 121 100 document.getElementById("enddatetime").value = date.toISOString().slice(0, 16); … … 131 110 var appointment = {}; 132 111 var business = {}; 133 business['id'] = parseInt($( "#company").val());134 appointment['service'] = {'id': parseInt($( "#service").val()), 'business':business};112 business['id'] = parseInt($('#company').attr('business-id')); 113 appointment['service'] = {'id': parseInt($('#service').attr('service-id')), 'business':business}; 135 114 appointment['startTime'] = $("#startdatetime").val(); 115 console.log(appointment); 136 116 137 117 $.ajax({ … … 143 123 success: function(succ){ 144 124 alert("Successful appointment!"); 145 var companyId = parseInt($( "#company").find(':selected').val());125 var companyId = parseInt($('#company').attr('business-id')); 146 126 getAppointmentsByBusiness(companyId, events); 147 127 destroyCalendar(); … … 154 134 }); 155 135 136 $('#search-input').keypress(function (e) { 137 138 var key = e.which; 139 if(key === 13) { // the enter key code 140 searchServices(); 141 return false; 142 } 143 }); 144 156 145 }); 157 146 … … 176 165 element.append(defaultOption); 177 166 } 178 179 /*loadCalendar([{'title': 'Gjoko', 'start': '2023-09-01 01:00:00', 'end': '2023-09-01 01:30:00', 'allDay':false, 'color': 'blue'}])*/180 167 181 168 function getAppointmentsByBusiness(businessId, events) { … … 273 260 $(this).remove(); 274 261 } 275 console.log('dropped');276 262 277 263 }, 278 264 events: function (start, end, callback) { 279 var selectedVal = $( "#company").find(':selected').val();265 var selectedVal = $('#company').attr('business-id'); 280 266 if(!isNaN(parseInt(selectedVal))) { 281 267 $.ajax({ … … 358 344 } 359 345 346 function searchServices() { 347 let value = document.getElementById("search-input").value; 348 $.ajax({ 349 type: 'GET', 350 url: "http://localhost:8080/api/service?searchKeyword=" + value, 351 success: function(data, textStatus, request) { 352 353 // clear previous data 354 $('#searchResultsModalBody').html(''); 355 356 if (data.length === 0) { 357 showNoSearchResultsFound(); 358 } else { 359 showSearchResults(data); 360 } 361 362 }, 363 error: function (request, textStatus, errorThrown) { 364 console.log(errorThrown); 365 } 366 }); 367 } 368 369 function showSearchResults(data) { 370 var searchResultsBody = $('#searchResultsModalBody') 371 searchResultsBody.append( 372 '<div class="form-outline col-lg-12 row">\n' + 373 ' <div class="form-outline col-lg-12">\n' + 374 ' <div class="table-responsive">\n' + 375 ' <table class="table">\n' + 376 ' <thead>\n' + 377 ' <tr>\n' + 378 ' <th scope="col">#</th>\n' + 379 ' <th scope="col">Business</th>\n' + 380 ' <th scope="col">Service name</th>\n' + 381 ' <th scope="col">Service Description</th>\n' + 382 ' <th scope="col">Durantion/Price</th>\n' + 383 ' <th scope="col">Rating/ReviewCount</th>\n' + 384 ' <th scope="col">Make reserviation</th>\n' + 385 ' </tr>\n' + 386 ' </thead>\n' + 387 ' <tbody id="search-results-table-body">\n' + 388 ' </tbody>\n' + 389 ' </table>\n' + 390 ' </div>\n' + 391 ' </div>\n' + 392 ' </div>'); 393 let $el = $('#search-results-table-body'); 394 395 $.each(data, function (index, obj) { 396 var element= 397 '<tr>' + 398 ' <th scope="row">' + (parseInt(index) + 1) + '</th>' + 399 ' <td>' + obj['businessName'] + '</td>' + 400 ' <td>' + obj['serviceName'] + '</td>' + 401 ' <td>' + obj['description'] + '</td>' + 402 ' <td>' + obj['duration'] + '/' + obj['price'] + '</td>' + 403 ' <td>' + obj['rating'] + '/' + obj['reviewsCount'] + '</td>' + 404 ' <td><button type="button" class="btn btn-primary" ' + 'onclick="makeReservation(\'' + obj['serviceName'] + '\',' + obj['rating'] + ',' + obj['reviewsCount'] + ',' + obj['id'] + ',\'' + obj['businessName'] + '\',' + obj['businessId'] + ',' + obj['duration'] + ')" ' + '>Reserve</button></td>' + 405 '</tr>'; 406 407 $el.append(element); 408 }); 409 410 $('#searchModal').modal('show'); 411 } 412 413 function makeReservation(name, value, count, serviceId, businessName, businessId, duration) { 414 $('#searchModal').modal('hide'); 415 $('#body-after-search').css("display", "inline"); 416 $('#welcome-message').css('display', 'none'); 417 $('#calendar').fullCalendar('render'); 418 setRatingCard(name, value, count, serviceId); 419 $('#company').val(businessName); 420 $('#company').attr('business-id', businessId); 421 $('#service').val(name); 422 $('#service').attr('duration', duration); 423 $('#service').attr('service-id', serviceId); 424 $('#calendar').fullCalendar('refetchEvents'); 425 } 426 427 function showNoSearchResultsFound() { 428 $('#searchResultsModalBody').text('Sorry we have no results for the thing that you search, please close the modal and search for something else.'); 429 $('#searchModal').modal('show'); 430 } 431 360 432 function generateStars(number) { 361 433 return '☆'.repeat(number); -
src/main/resources/static/js/register_business.js
re8999eb rf29cd58 17 17 var $el = $("#predefined_services"); 18 18 $el.empty(); 19 console.log(selectedObj['serviceTypes']); 19 20 $.each(selectedObj['serviceTypes'], function (index, obj) { 20 21 $el.append( 21 '<div class= \"form-outline mb-4\">' +22 '<div class="form-outline mb-4">' + 22 23 ' <div class="row">' + 23 24 ' <div class="col-md-6">\n' + 24 ' <input class="form-check-input" type="checkbox" value= \"' + obj.id + '\" id=\"' + obj.id + '\">\n' +25 ' <label class="form-check-label" for= \"' + obj.id + '\">\n' +25 ' <input class="form-check-input" type="checkbox" value="' + obj.id + '" id="' + obj.id + '">\n' + 26 ' <label class="form-check-label" for="' + obj.id + '">\n' + 26 27 obj.name + 27 28 ' </label>\n' + 28 29 ' </div>' + 29 ' <div class= \"form-outline col-md-2 d-grid\">' +30 ' <input type= \"text\" id=\"' + obj.id + obj.name.replace(/\s/g, "") + "duration" + '\" class=\"form-control\" placeholder="time" />' +30 ' <div class="form-outline col-md-2 d-grid">' + 31 ' <input type="text" id="' + obj.id + obj.name.replace(/\s/g, "") + "duration" + '" class="form-control" placeholder="time" />' + 31 32 ' </div>' + 32 ' <div class=\"form-outline col-md-2 d-grid\">' + 33 ' <input type=\"text\" id=\"' + obj.id + obj.name.replace(/\s/g, "") + "price" + '\" class=\"form-control\" placeholder="price" />' + 33 ' <div class="form-outline col-md-2 d-grid">' + 34 ' <input type="text" id="' + obj.id + obj.name.replace(/\s/g, "") + "price" + '" class="form-control" placeholder="price" />' + 35 ' </div>' + 36 ' </div>' + 37 ' <div class="row" style="margin-top:10px;">' + 38 ' <div class="form-outline col-md-10 d-grid">' + 39 ' <input type="text" id="' + obj.id + obj.name.replace(/\s/g, "") + "description" + '" class="form-control" placeholder="description" />' + 34 40 ' </div>' + 35 41 ' </div>' + … … 58 64 ' </div>' + 59 65 ' <div class="form-outline col-md-2 d-grid">' + 60 ' <input type="text" id="' + -1 + input_service.replace(/\s/g, "") + "price"+ '" class="form-control" placeholder="price" />' + 66 ' <input type="text" id="' + -1 + input_service.replace(/\s/g, "") + "price" + '" class="form-control" placeholder="price" />' + 67 ' </div>' + 68 ' <div class="row" style="margin-top:10px;">' + 69 ' <div class="form-outline col-md-10 d-grid">' + 70 ' <input type="text" id="' + -1 + input_service.replace(/\s/g, "") + "description" + '" class="form-control" placeholder="description" />' + 71 ' </div>' + 61 72 ' </div>' + 62 73 ' </div>' + … … 90 101 var time = $($($(label).parent()).siblings()[0]).children()[0].value; 91 102 var price = $($($(label).parent()).siblings()[1]).children()[0].value; 103 var description = $($($($($($(label).parent())).parent()).siblings()[0]).children()[0]).children()[0].value; 92 104 93 105 var serviceType = {} … … 99 111 service['duration'] = time; 100 112 service['price'] = price; 113 service['description'] = description; 101 114 servicesObj.push(service); 102 115 }); -
src/main/resources/templates/homepage.html
re8999eb rf29cd58 16 16 <link href='css/fullcalendar.print.css' rel='stylesheet' media='print'/> 17 17 <link href="css/homepage.css" rel="stylesheet"/> 18 <link href="css/headers.css" rel="stylesheet" 18 <link href="css/headers.css" rel="stylesheet"/> 19 19 </head> 20 20 <body> … … 23 23 <header class="p-3 mb-3 border-bottom"> 24 24 <div class="row" style="justify-content: space-between;"> 25 <div class="col-md- 8 mb-8">25 <div class="col-md-4 mb-4"> 26 26 Welcome to the Schedlr 27 </div> 28 <div class="col-md-3 mb-3"> 29 <input class="form-control mr-sm-2" id="search-input" type="search" placeholder="Search" aria-label="Find services"> 30 </div> 31 32 <div class="col-md-1 mb-1"> 33 <button id="search" class="btn btn-primary btn-block" onclick="searchServices()"> 34 Search 35 </button> 27 36 </div> 28 37 <div class="col-md-2 mb-2"> … … 45 54 <!-- Navbar end --> 46 55 <div class="container"> 47 <div id='wrap'> 48 <div id='calendar'></div> 49 <div style='clear:both'></div> 50 </div> 51 52 53 <div class="card"> 54 <div class="form-outline mb-4"> 55 <select class="form-select" id="companyType" aria-label="Select company type"> 56 <option disabled selected hidden>Company Type</option> 57 </select> 56 <div id='body-after-search' style="display:none;"> 57 <div id='wrap'> 58 <div id='calendar'></div> 59 <div style='clear:both'></div> 60 </div> 61 <div class="card"> 62 <div class="form-outline mb-4"> 63 <input id="company" disabled class="form-control" placeholder="company" 64 aria-label="company"/> 65 </div> 66 <div class="form-outline mb-4"> 67 <input id="service" disabled class="form-control" placeholder="service" 68 aria-label="service"/> 69 </div> 70 <div class="form-outline mb-4"> 71 <label for="startdatetime">Start:</label> 72 <input type="datetime-local" id="startdatetime" name="startdatetime" style="float:right;"> 73 </div> 74 <div class="form-outline mb-4"> 75 <label for="enddatetime">End:</label> 76 <input type="datetime-local" id="enddatetime" name="enddatetime" style="float:right;"> 77 </div> 78 <div class="form-outline mb-4"> 79 <button id="createAppointment" class="btn btn-primary btn-block"> 80 Create Appointment 81 </button> 82 </div> 83 </div> 84 <div class="card form-outline mb-4" style="margin-top:30px;"> 85 <ul class="list-group list-group-flush" id="reviews-ul"> 86 <li class="list-group-item"><b>service name: </b><span id="rating-service-name"></span></li> 87 <li class="list-group-item"><b>rating </b><span id="rating-value"></span></li> 88 <li class="list-group-item" style="margin-bottom:10px;"><b>reviews count </b><span 89 id="rating-count"></span></li> 90 <li class="list-group-item" id="reviews-li"><a href="#/reviews_page">Checkout reviews</a></li> 91 </ul> 58 92 </div> 59 93 60 <div class="form-outline mb-4"> 61 <select class="form-select" id="company" aria-label="Select company"> 62 <option disabled selected hidden>Company</option> 63 </select> 64 </div> 65 <div class="form-outline mb-4"> 66 <select class="form-select" id="service" aria-label="Select service"> 67 <option disabled selected hidden>Service</option> 68 </select> 69 </div> 70 <div class="form-outline mb-4"> 71 <label for="startdatetime">Start:</label> 72 <input type="datetime-local" id="startdatetime" name="startdatetime" style="float:right;"> 73 </div> 74 <div class="form-outline mb-4"> 75 <label for="enddatetime">End:</label> 76 <input type="datetime-local" id="enddatetime" name="enddatetime" style="float:right;"> 77 </div> 78 <div class="form-outline mb-4"> 79 <button id="createAppointment" class="btn btn-primary btn-block"> 80 Create Appointment 81 </button> 94 </div> 95 <div id="welcome-message" class="welcome_message"> 96 <div class="card text-center"> 97 <div class="card-body"> 98 <h1 class="card-title"> 99 Welcome to Schedlr, please you the search bar to find the services you want. 100 </h1> 101 </div> 82 102 </div> 83 103 </div> 84 <div class="card form-outline mb-4" style="margin-top:30px;" > 85 <ul class="list-group list-group-flush" id="reviews-ul"> 86 <li class="list-group-item"><b>service name: </b><span id="rating-service-name"></span></li> 87 <li class="list-group-item"><b>rating </b><span id="rating-value"></span></li> 88 <li class="list-group-item" style="margin-bottom:10px;"><b>reviews count </b><span id="rating-count"></span></li> 89 <li class="list-group-item" id="reviews-li"><a href="#/reviews_page">Checkout reviews</a></li> 90 </ul> 91 </div> 92 93 </div> 94 <div class="modal fade" id="showReviewsModal" tabindex="-1" aria-labelledby="showReviewsModalLabel" aria-hidden="true"> 95 <div class="modal-dialog modal-xl modal-dialog-scrollable modal-dialog-centered" > 96 <div class="modal-content"> 97 <div class="modal-header"> 98 <h1>Reviews</h1> 99 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 100 </div> 101 <div class="modal-body form-outline col-lg-12 row" id="reviewsModalBody" style="--mdb-gutter-x: 0 !important; background-color: #f0f0f0 !important;"> 102 <div class="card m-3" style="max-width: 300px; padding: 0;"> 103 <div class="card-header text-bg-success"> 104 ☆☆☆☆☆ 105 </div> 106 <ul class="list-group list-group-flush"> 107 <li class="list-group-item"><i>Business:</i> Businessname<</li> 108 <li class="list-group-item"><i>Service:</i> Customer Name</li> 109 <li class="list-group-item"><i>Reviewer:</i> Customer Name</li> 110 <li class="list-group-item"><i>Comment:</i> Lorem ipsum diem amet</li> 111 <li class="list-group-item"><small class="text-body-secondary">Created on 29-11-2023T11:32:23</small></li> 112 </ul> 104 <div class="modal fade" id="showReviewsModal" tabindex="-1" aria-labelledby="showReviewsModalLabel" 105 aria-hidden="true"> 106 <div class="modal-dialog modal-xl modal-dialog-scrollable modal-dialog-centered"> 107 <div class="modal-content"> 108 <div class="modal-header"> 109 <h1>Reviews</h1> 110 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 111 </div> 112 <div class="modal-body form-outline col-lg-12 row" id="reviewsModalBody" 113 style="--mdb-gutter-x: 0 !important; background-color: #f0f0f0 !important;"> 114 </div> 115 <div class="modal-footer"> 116 <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> 113 117 </div> 114 118 </div> 115 <div class="modal-footer"> 116 <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> 119 </div> 120 </div> 121 <div class="modal fade" id="searchModal" tabindex="-1" aria-labelledby="showSearchResultsModalLabel" aria-hidden="true"> 122 <div class="modal-dialog modal-xl modal-dialog-scrollable modal-dialog-centered"> 123 <div class="modal-content"> 124 <div class="modal-header"> 125 <h1>Search results</h1> 126 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 127 </div> 128 <div class="modal-body form-outline col-lg-12 row" id="searchResultsModalBody" 129 style="--mdb-gutter-x: 0 !important; background-color: #f0f0f0 !important;"> 130 </div> 131 <div class="modal-footer"> 132 <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> 133 </div> 117 134 </div> 118 135 </div> 136 119 137 </div> 120 138 </div>
Note:
See TracChangeset
for help on using the changeset viewer.