diff --git a/application/controllers/Admin.php b/application/controllers/Admin.php index 8db679c..1c4ba56 100755 --- a/application/controllers/Admin.php +++ b/application/controllers/Admin.php @@ -547,6 +547,13 @@ class Admin extends CI_Controller { $data['selectedItem'] = $this->Service_model->getWorkerById($worker_id); // Verticals are derived from the worker's service category, not stored. $data['workerVerticals'] = $this->Service_model->getVerticalsForWorker($worker_id); + + // Capability grid: which of the category's services this worker performs. + // An empty stored set means unrestricted, which the view renders as + // everything ticked - see the note in the form. + $data['categoryServices'] = $this->Service_model->getServicesByCategoryId($data['selectedItem']->service_category_id); + $data['workerServiceIds'] = $this->Service_model->getWorkerServiceIds($worker_id); + $this->load->view('admin/update-worker', $data); } else{ @@ -554,6 +561,48 @@ class Admin extends CI_Controller { } } + /** + * Translate the PHP upload error code for the worker profile picture into + * an admin-facing message. + * + * The upload blocks below used to gate on tmp_name alone, which made a + * REJECTED upload indistinguishable from "no file chosen": PHP empties + * tmp_name in both cases, so an oversized photo was skipped in silence and + * the worker was saved with an empty worker_profile_img. Reading the error + * code is the only way to tell the two apart. + * + * @return string '' when there is nothing to report (no file chosen, or a + * file that arrived intact), otherwise the message to show. + */ + private function _workerImgUploadError(){ + // No file part at all - nothing was submitted, nothing to report. + if(!isset($_FILES['worker_img']) || !isset($_FILES['worker_img']['error'])){ + return ''; + } + + switch($_FILES['worker_img']['error']){ + case UPLOAD_ERR_OK: + case UPLOAD_ERR_NO_FILE: + // Intact, or the admin simply left the field empty. + return ''; + + case UPLOAD_ERR_INI_SIZE: + case UPLOAD_ERR_FORM_SIZE: + return 'A kép túl nagy! A megengedett legnagyobb méret: '.ini_get('upload_max_filesize').'.'; + + case UPLOAD_ERR_PARTIAL: + return 'A kép csak részben töltődött fel. Kérlek próbáld újra!'; + + case UPLOAD_ERR_NO_TMP_DIR: + case UPLOAD_ERR_CANT_WRITE: + case UPLOAD_ERR_EXTENSION: + return 'A kép feltöltése szerverhiba miatt nem sikerült. Szólj az üzemeltetőnek!'; + + default: + return 'Ismeretlen hiba a kép feltöltése közben.'; + } + } + public function worker_process(){ $this->load->helper('url'); $this->load->model('User_model'); @@ -565,7 +614,16 @@ class Admin extends CI_Controller { $data['pageTitle'] = ''; $data['message'] = ''; $data['message_class'] = ''; - + + // A POST body larger than post_max_size is discarded WHOLESALE by PHP: + // $_POST and $_FILES both arrive empty, so none of the branches below + // fire and the form appears to do nothing at all. CONTENT_LENGTH still + // reports the real size, which is the only surviving evidence. + if($_SERVER['REQUEST_METHOD'] === 'POST' && empty($_POST) && !empty($_SERVER['CONTENT_LENGTH'])){ + $data['message'] = 'A beküldött adat túl nagy volt, ezért a mentés nem történt meg. A kép legfeljebb '.ini_get('upload_max_filesize').' lehet.'; + $data['message_class'] = 'errorMessage'; + } + if(isset($_GET['delete-worker'])){ $selected_worker = $this->Service_model->getWorkerById($_GET['delete-worker']); $workerArray = array( @@ -581,7 +639,12 @@ class Admin extends CI_Controller { $data['worker_img'] = ''; - if($_FILES["worker_img"]["tmp_name"] != ''){ + $workerImgError = $this->_workerImgUploadError(); + + if($workerImgError !== ''){ + $data['message'] = $workerImgError; + $data['message_class'] = 'errorMessage'; + } elseif($_FILES["worker_img"]["tmp_name"] != ''){ $target_dir = getcwd()."/assets/img/"; $target_file = $target_dir . 'worker_'.str_replace(' ','_', $_POST['worker_name']); $imageFileType = strtolower(pathinfo(basename($_FILES["worker_img"]["name"]),PATHINFO_EXTENSION)); @@ -632,7 +695,44 @@ class Admin extends CI_Controller { $this->Service_model->updateWorker($_POST['worker_id'], $workerArray); $this->Log_model->addLog('workers', $data['currentUser']->username.' módosította a(z) '.$_POST['worker_name'].' nevű dolgozót ('.implode(',',$workerArray).')', $data['currentUser']->username); - if($_FILES["worker_img"]["tmp_name"] != ''){ + // Capability set. The grid posts the ticked service ids; anything not + // belonging to the worker's (possibly just-changed) category is dropped + // so a category switch cannot leave orphaned rows behind. + $postedServiceIds = isset($_POST['worker_services']) && is_array($_POST['worker_services']) + ? $_POST['worker_services'] + : array(); + + $categoryServices = $this->Service_model->getServicesByCategoryId($_POST['service_category_id']); + $categoryServiceIds = array(); + if(is_array($categoryServices)){ + foreach($categoryServices as $svc){ + $categoryServiceIds[] = (int)$svc->service_id; + } + } + + $allowedServiceIds = array(); + foreach($postedServiceIds as $postedId){ + if(in_array((int)$postedId, $categoryServiceIds, TRUE)){ + $allowedServiceIds[] = (int)$postedId; + } + } + + // Every service ticked means "no restriction": store nothing, so the + // worker keeps performing services added in the future too. Storing the + // full set instead would silently freeze them out of every new service. + if(count($allowedServiceIds) === count($categoryServiceIds)){ + $allowedServiceIds = array(); + } + + $this->Service_model->setWorkerServiceIds($_POST['worker_id'], $allowedServiceIds); + $this->Log_model->addLog('workers', $data['currentUser']->username.' beállította a(z) '.$_POST['worker_name'].' nevű dolgozó végezhető szolgáltatásait ('.(empty($allowedServiceIds) ? 'nincs korlátozás' : implode(',', $allowedServiceIds)).')', $data['currentUser']->username); + + $workerImgError = $this->_workerImgUploadError(); + + if($workerImgError !== ''){ + $data['message'] = $workerImgError; + $data['message_class'] = 'errorMessage'; + } elseif($_FILES["worker_img"]["tmp_name"] != ''){ $target_dir = getcwd()."/assets/img/"; $target_file = $target_dir . 'worker_'.str_replace(' ','_', $_POST['worker_name']); $imageFileType = strtolower(pathinfo(basename($_FILES["worker_img"]["name"]),PATHINFO_EXTENSION)); diff --git a/application/controllers/Pages.php b/application/controllers/Pages.php index a63be1d..68f9662 100755 --- a/application/controllers/Pages.php +++ b/application/controllers/Pages.php @@ -137,7 +137,15 @@ class Pages extends CI_Controller { $data['pageTitle'] = ''; if(isset($_POST['action']) && $_POST['action'] == 'getAvailableWorkersByServiceCategory' && isset($_POST['serv_cat_slug'])){ - $workers = $this->Service_model->getWorkersByCategorySlug($_POST['serv_cat_slug']); + // The picker must only offer workers who can perform EVERY service the + // guest has ticked. service_ids is supplied by the booking form; when it + // is absent (older cached JS) the call degrades to the category-only + // behaviour rather than returning nobody. + $requestedServiceIds = isset($_POST['service_ids']) && is_array($_POST['service_ids']) + ? $_POST['service_ids'] + : array(); + + $workers = $this->Service_model->getWorkersByCategorySlug($_POST['serv_cat_slug'], $requestedServiceIds); $returnedWorkers = ''; $workerIndex = 0; $workerListShow = ''; @@ -445,6 +453,15 @@ class Pages extends CI_Controller { } } + // Per-worker capability. The category check above only proves the + // services belong to the worker's category - not that this particular + // worker performs them. The picker already hides incapable workers, but + // that is a UI affordance, so re-check before the booking is written. + if (!$this->Service_model->workerCanPerformServices($bookingArray['worker_id'], $selectedServiceArray)) { + $this->_booking_error('service_not_offered', 403); + return; + } + // Single-service verticals: the client disables the other checkboxes, // but that is a UI affordance only. The vertical is derived from the // services themselves rather than $_POST['subpage'], which is @@ -883,7 +900,7 @@ class Pages extends CI_Controller { } } if($categorySlug !== ''){ - $data['workers'] = $this->Service_model->getWorkersByCategorySlug($categorySlug); + $data['workers'] = $this->Service_model->getWorkersByCategorySlug($categorySlug, is_array($serviceIds) ? $serviceIds : array()); } else { $data['workers'] = $this->Service_model->getActiveWorkers($subpage); } @@ -952,6 +969,15 @@ class Pages extends CI_Controller { } } + // Per-worker capability, same reasoning as booking_process(): the + // category check proves only that the services belong to the worker's + // category, not that this worker performs them. + if(!$this->Service_model->workerCanPerformServices($newWorkerId, $selectedServiceArray)){ + $this->output->set_status_header(403)->set_content_type('application/json') + ->set_output(json_encode(['error' => 'Selected worker does not perform the chosen services.'])); + return; + } + // Schedule check $schedule = $this->Service_model->getWorkerScheduleForDate($newWorkerId, $newBookingDate); if(!$schedule){ diff --git a/application/models/Service_model.php b/application/models/Service_model.php index 9672d99..f5eb020 100755 --- a/application/models/Service_model.php +++ b/application/models/Service_model.php @@ -127,20 +127,28 @@ class Service_model extends CI_Model { $this->_applyLegacyVerticalFlags($workerArray, $workerArray['service_category_id']); + // is_active was previously omitted from this INSERT, so the column + // default (1) always won and a worker created as inactive silently + // came back active. The admin's choice is honoured here; callers that + // do not supply it still get the old default. + $is_active = isset($workerArray['is_active']) ? (int)$workerArray['is_active'] : 1; + $query = $this->db->query('INSERT INTO workers ( worker_name, worker_profile_img, worker_info, is_beauty, is_barber, - service_category_id - ) VALUES(?, ?, ?, ?, ?, ?)', array( + service_category_id, + is_active + ) VALUES(?, ?, ?, ?, ?, ?, ?)', array( $workerArray['worker_name'], $workerArray['worker_profile_img'], $workerArray['worker_info'], $workerArray['is_beauty'], $workerArray['is_barber'], - $workerArray['service_category_id'] + $workerArray['service_category_id'], + $is_active )); } @@ -243,6 +251,25 @@ class Service_model extends CI_Model { } } + /** + * Live services belonging to one category, ordered for display as the + * admin capability grid (sub-heading, then name). + * + * @param int $service_category_id + * @return array + */ + public function getServicesByCategoryId($service_category_id){ + $this->load->database(); + $query = $this->db->query( + 'SELECT * FROM services + WHERE service_category_id = ? AND is_deleted != "1" + ORDER BY service_type ASC, service_category_no ASC, service_id ASC', + array($service_category_id) + ); + + return $query->result(); + } + public function getAllServiceCategories(){ $this->load->database(); $query = $this->db->query('SELECT * FROM service_categories WHERE is_deleted != "1" ORDER BY service_category_id;'); @@ -300,9 +327,161 @@ class Service_model extends CI_Model { return $query->result(); } - public function getWorkersByCategorySlug($serv_cat_slug){ + /** + * The service ids one worker is allowed to perform. + * + * An EMPTY result means "unrestricted" - the worker performs every live + * service in their category, which is how every worker behaved before + * worker_services existed. Restrictions are therefore opt-in per worker, + * and a missing migration degrades to the old behaviour instead of + * hiding everybody from the booking flow. + * + * @param int $worker_id + * @return array list of service_id ints (empty = unrestricted) + */ + public function getWorkerServiceIds($worker_id){ $this->load->database(); - $query = $this->db->query('SELECT * FROM workers JOIN service_categories ON workers.service_category_id = service_categories.service_category_id WHERE workers.is_deleted != "1" AND serv_cat_slug = ? ORDER BY worker_name ASC', array($serv_cat_slug)); + $query = $this->db->query( + 'SELECT service_id FROM worker_services WHERE worker_id = ? ORDER BY service_id ASC', + array($worker_id) + ); + + $ids = array(); + foreach($query->result() as $row){ + $ids[] = (int)$row->service_id; + } + + return $ids; + } + + /** + * Replace a worker's allowed-service set. + * + * Passing an empty array clears every row, which restores the worker to + * the unrestricted default rather than making them unable to do anything. + * + * @param int $worker_id + * @param array $service_ids + * @return void + */ + public function setWorkerServiceIds($worker_id, $service_ids){ + $this->load->database(); + + $this->db->query('DELETE FROM worker_services WHERE worker_id = ?', array($worker_id)); + + if(!is_array($service_ids) || empty($service_ids)){ + return; + } + + // De-duplicate: the PK would reject repeats and abort the whole save. + $clean = array(); + foreach($service_ids as $service_id){ + $service_id = (int)$service_id; + if($service_id > 0){ + $clean[$service_id] = TRUE; + } + } + + foreach(array_keys($clean) as $service_id){ + $this->db->query( + 'INSERT INTO worker_services (worker_id, service_id) VALUES (?, ?)', + array($worker_id, $service_id) + ); + } + } + + /** + * Can this worker perform EVERY one of these services? + * + * Used as the server-side guard behind the worker picker: the picker only + * offers capable workers, but that is a UI affordance and a crafted POST + * must not get past it. + * + * @param int $worker_id + * @param array $service_ids + * @return bool + */ + public function workerCanPerformServices($worker_id, $service_ids){ + if(!is_array($service_ids) || empty($service_ids)){ + return TRUE; + } + + $allowed = $this->getWorkerServiceIds($worker_id); + + // No rows at all = unrestricted worker. + if(empty($allowed)){ + return TRUE; + } + + foreach($service_ids as $service_id){ + if(!in_array((int)$service_id, $allowed, TRUE)){ + return FALSE; + } + } + + return TRUE; + } + + /** + * Bookable workers for one service category, optionally narrowed to those + * able to perform a specific set of services. + * + * Both callers are guest-facing (the booking worker picker and the + * manage-booking worker list), so an INACTIVE worker must not appear: + * this used to filter on is_deleted alone, which meant switching a + * worker to inactive in the admin had no effect on the public flow. + * getActiveWorkers() - the fallback used by the very same caller when + * no category is known - has always filtered on is_active; the two + * paths now agree. + * + * @param string $serv_cat_slug + * @param array $service_ids selected services; empty = no capability filter + * @return array + */ + public function getWorkersByCategorySlug($serv_cat_slug, $service_ids = array()){ + $this->load->database(); + + $sql = 'SELECT w.* FROM workers w + JOIN service_categories sc ON w.service_category_id = sc.service_category_id + WHERE w.is_deleted != "1" AND w.is_active = "1" AND sc.serv_cat_slug = ?'; + $params = array($serv_cat_slug); + + // Capability filter. A worker qualifies when they are unrestricted (no + // worker_services rows at all) OR their allowed set covers EVERY + // selected service - counting matched rows against the number asked + // for, so a worker who can do 2 of the 3 chosen services is excluded. + $clean = array(); + if(is_array($service_ids)){ + foreach($service_ids as $service_id){ + $service_id = (int)$service_id; + if($service_id > 0){ + $clean[$service_id] = TRUE; + } + } + } + $clean = array_keys($clean); + + if(!empty($clean)){ + $placeholders = implode(',', array_fill(0, count($clean), '?')); + + $sql .= ' AND ( + NOT EXISTS (SELECT 1 FROM worker_services wsx WHERE wsx.worker_id = w.worker_id) + OR ( + SELECT COUNT(*) FROM worker_services ws + WHERE ws.worker_id = w.worker_id + AND ws.service_id IN ('.$placeholders.') + ) = ? + )'; + + foreach($clean as $service_id){ + $params[] = $service_id; + } + $params[] = count($clean); + } + + $sql .= ' ORDER BY w.worker_name ASC'; + + $query = $this->db->query($sql, $params); return $query->result(); } diff --git a/application/views/admin/includes/update-worker-form.php b/application/views/admin/includes/update-worker-form.php index 3a8b4a3..d56c215 100755 --- a/application/views/admin/includes/update-worker-form.php +++ b/application/views/admin/includes/update-worker-form.php @@ -1,3 +1,144 @@ + +
@@ -72,6 +213,76 @@
+
+
Végezhető szolgáltatások
+
+ Csak a bepipált szolgáltatásokat ajánlja fel a foglalási rendszer ennél a dolgozónál. + Ha mindegyik be van pipálva, a dolgozó korlátozás nélkül dolgozik, és a + később felvett új szolgáltatásokat is automatikusan végezheti. Ha akár egyet is kiveszel, + a dolgozó korlátozott lesz, és az ezután létrehozott új szolgáltatásokat külön be kell + majd pipálni neki. +
+ 0; + + if($wsHasServices){ + // Group first so each heading can be rendered as its own table. + $wsGroups = array(); + foreach($categoryServices as $svc){ + $wsGroups[$svc->service_type.' - '.$svc->service_category_no][] = $svc; + } +?> +
+ + + +
+ +
+ $wsRows){ +?> + + + + +service_id, $wsIds, TRUE); + $svcName = $svc->service_name_hu !== '' ? $svc->service_name_hu : $svc->service_name_no; +?> + + + + + +
+ > + + +
+ +
+ +
Ehhez a kategóriához nincs szolgáltatás.
+ +
Mégsem @@ -79,3 +290,38 @@
+ + diff --git a/application/views/pages/includes/barber-form-en.php b/application/views/pages/includes/barber-form-en.php index 7ffb6b2..55d380f 100755 --- a/application/views/pages/includes/barber-form-en.php +++ b/application/views/pages/includes/barber-form-en.php @@ -100,6 +100,21 @@ + +
+
+ +

AMARILDO Champimpi - Barber

+
+ diff --git a/application/views/pages/includes/barber-form-hu.php b/application/views/pages/includes/barber-form-hu.php index 05cd6fe..0449c68 100755 --- a/application/views/pages/includes/barber-form-hu.php +++ b/application/views/pages/includes/barber-form-hu.php @@ -76,6 +76,21 @@ + +
+
+ +

AMARILDO Champimpi - Barber

+
+ diff --git a/application/views/pages/includes/barber-form-no.php b/application/views/pages/includes/barber-form-no.php index 15d6780..f84aaaf 100755 --- a/application/views/pages/includes/barber-form-no.php +++ b/application/views/pages/includes/barber-form-no.php @@ -77,6 +77,21 @@ + +
+
+ +

AMARILDO Champimpi - Barber

+
+ diff --git a/application/views/pages/includes/booking-error-form-en.php b/application/views/pages/includes/booking-error-form-en.php index 48f60f0..5d942a5 100755 --- a/application/views/pages/includes/booking-error-form-en.php +++ b/application/views/pages/includes/booking-error-form-en.php @@ -7,6 +7,7 @@ 'after_hours' => 'The treatment would not finish before closing time. Please choose an earlier time.', 'too_far' => 'Bookings can only be made up to 3 months in advance.', 'category_mismatch' => 'The selected staff member does not perform the chosen services. Please start again.', + 'service_not_offered' => 'The selected staff member does not perform all of the chosen treatments. Please pick another staff member or change the treatments.', 'single_service_only' => 'Only one treatment can be booked at a time. Please select just one.', 'invalid_email' => 'That e-mail address does not look valid. Please check it - your confirmation and the link to manage your booking are sent there.', 'no_service' => 'No service was selected. Please choose at least one service.', diff --git a/application/views/pages/includes/booking-error-form-hu.php b/application/views/pages/includes/booking-error-form-hu.php index 0464482..84d67a6 100755 --- a/application/views/pages/includes/booking-error-form-hu.php +++ b/application/views/pages/includes/booking-error-form-hu.php @@ -7,6 +7,7 @@ 'after_hours' => 'A kezelés nem érne véget zárásig. Kérjük, válasszon korábbi időpontot.', 'too_far' => 'Foglalás legfeljebb 3 hónappal előre adható le.', 'category_mismatch' => 'A kiválasztott kolléga nem végzi a kiválasztott szolgáltatásokat. Kérjük, válasszon újra.', + 'service_not_offered' => 'A kiválasztott kolléga nem végzi el az összes kiválasztott szolgáltatást. Kérjük, válasszon másik kollégát, vagy módosítsa a szolgáltatásokat.', 'single_service_only' => 'Egyszerre csak egy kezelés foglalható. Kérjük, csak egyet válasszon.', 'invalid_email' => 'Az e-mail cím nem tűnik érvényesnek. Kérjük, ellenőrizze - a visszaigazolást és a foglalás kezelésére szolgáló linket erre a címre küldjük.', 'no_service' => 'Nem választott ki szolgáltatást. Kérjük, válasszon legalább egyet.', diff --git a/application/views/pages/includes/booking-error-form-no.php b/application/views/pages/includes/booking-error-form-no.php index b419dc2..ef8e172 100755 --- a/application/views/pages/includes/booking-error-form-no.php +++ b/application/views/pages/includes/booking-error-form-no.php @@ -7,6 +7,7 @@ 'after_hours' => 'Behandlingen rekker ikke å bli ferdig innen stengetid. Vennligst velg et tidligere tidspunkt.', 'too_far' => 'Du kan kun bestille time inntil 3 måneder frem i tid.', 'category_mismatch' => 'Den valgte medarbeideren utfører ikke de valgte tjenestene. Vennligst velg på nytt.', + 'service_not_offered' => 'Den valgte medarbeideren utfører ikke alle de valgte behandlingene. Vennligst velg en annen medarbeider eller endre behandlingene.', 'single_service_only' => 'Du kan kun bestille én behandling om gangen. Vennligst velg kun én.', 'invalid_email' => 'E-postadressen ser ikke ut til å være gyldig. Vennligst kontroller den - bekreftelsen og lenken for å endre bestillingen sendes dit.', 'no_service' => 'Du har ikke valgt noen tjeneste. Vennligst velg minst én tjeneste.', diff --git a/application/views/pages/includes/booking-form-en.php b/application/views/pages/includes/booking-form-en.php index 46548c3..6fd2fd7 100755 --- a/application/views/pages/includes/booking-form-en.php +++ b/application/views/pages/includes/booking-form-en.php @@ -364,12 +364,19 @@ } function getAvailableWorkersByServiceCategorySlug(categorySlug){ + // Only workers who can perform EVERY ticked service may be offered. + // The checkbox id IS the service_id (see the service list markup). + var selectedServiceIds = $('.service:checked').map(function(){ + return this.id; + }).get(); + $.ajax({ url: 'ajax', type: 'POST', data: { action:'getAvailableWorkersByServiceCategory', - serv_cat_slug:categorySlug + serv_cat_slug:categorySlug, + service_ids:selectedServiceIds }, error: function() { }, diff --git a/application/views/pages/includes/booking-form-hu.php b/application/views/pages/includes/booking-form-hu.php index 01d6ff6..0e2a642 100755 --- a/application/views/pages/includes/booking-form-hu.php +++ b/application/views/pages/includes/booking-form-hu.php @@ -365,12 +365,19 @@ } function getAvailableWorkersByServiceCategorySlug(categorySlug){ + // Only workers who can perform EVERY ticked service may be offered. + // The checkbox id IS the service_id (see the service list markup). + var selectedServiceIds = $('.service:checked').map(function(){ + return this.id; + }).get(); + $.ajax({ url: 'ajax', type: 'POST', data: { action:'getAvailableWorkersByServiceCategory', - serv_cat_slug:categorySlug + serv_cat_slug:categorySlug, + service_ids:selectedServiceIds }, error: function() { }, diff --git a/application/views/pages/includes/booking-form-no.php b/application/views/pages/includes/booking-form-no.php index 3917631..86eb3b7 100755 --- a/application/views/pages/includes/booking-form-no.php +++ b/application/views/pages/includes/booking-form-no.php @@ -363,12 +363,19 @@ if (is_array($services) && count($services) > 0) { } function getAvailableWorkersByServiceCategorySlug(categorySlug){ + // Only workers who can perform EVERY ticked service may be offered. + // The checkbox id IS the service_id (see the service list markup). + var selectedServiceIds = $('.service:checked').map(function(){ + return this.id; + }).get(); + $.ajax({ url: 'ajax', type: 'POST', data: { action:'getAvailableWorkersByServiceCategory', - serv_cat_slug:categorySlug + serv_cat_slug:categorySlug, + service_ids:selectedServiceIds }, error: function() { }, diff --git a/assets/css/barber.css b/assets/css/barber.css index 76b14df..5909a18 100755 --- a/assets/css/barber.css +++ b/assets/css/barber.css @@ -3364,6 +3364,11 @@ input, select, textarea { } +/* Worker bio with no photo strip alongside - let the text use the full width. */ +.bemutatkozas-dolgozo.no-gallery .bem-dolgozo-bal{ + width: 100%; +} + /* Treatments - Our Services */ diff --git a/assets/img/barber/amarildo/amarildo.jpg b/assets/img/barber/amarildo/amarildo.jpg new file mode 100644 index 0000000..264664e Binary files /dev/null and b/assets/img/barber/amarildo/amarildo.jpg differ diff --git a/assets/img/worker_Amarildo_Champimpi.jpeg b/assets/img/worker_Amarildo_Champimpi.jpeg new file mode 100644 index 0000000..9bfa60f Binary files /dev/null and b/assets/img/worker_Amarildo_Champimpi.jpeg differ