Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8fe7724a2 | ||
|
|
5c30467fbd |
@@ -89,7 +89,7 @@ $autoload['drivers'] = array();
|
|||||||
|
|
|
|
||||||
| $autoload['helper'] = array('url', 'file');
|
| $autoload['helper'] = array('url', 'file');
|
||||||
*/
|
*/
|
||||||
$autoload['helper'] = array();
|
$autoload['helper'] = array('vertical');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
| -------------------------------------------------------------------
|
| -------------------------------------------------------------------
|
||||||
|
|||||||
@@ -60,6 +60,11 @@ $route['profile'] = 'pages/profile';
|
|||||||
$route['log-monitor'] = 'Pages/log_monitor';
|
$route['log-monitor'] = 'Pages/log_monitor';
|
||||||
$route['(:any)/barber'] = 'pages/barber/$1';
|
$route['(:any)/barber'] = 'pages/barber/$1';
|
||||||
$route['(:any)/beauty'] = 'pages/beauty/$1';
|
$route['(:any)/beauty'] = 'pages/beauty/$1';
|
||||||
|
// Verticals added after the registry was introduced dispatch through
|
||||||
|
// Pages::vertical(), which resolves branding and views from
|
||||||
|
// application/config/verticals.php. barber and beauty keep their original
|
||||||
|
// dedicated routes so their output stays byte-identical.
|
||||||
|
$route['(:any)/massage'] = 'pages/vertical/$1/massage';
|
||||||
$route['(:any)/booking/(:any)'] = 'pages/booking/$1/$2';
|
$route['(:any)/booking/(:any)'] = 'pages/booking/$1/$2';
|
||||||
$route['(:any)/booking-finished/(:any)'] = 'pages/booking_finished/$1/$2';
|
$route['(:any)/booking-finished/(:any)'] = 'pages/booking_finished/$1/$2';
|
||||||
$route['email-verification'] = 'pages/email_verification';
|
$route['email-verification'] = 'pages/email_verification';
|
||||||
|
|||||||
@@ -0,0 +1,168 @@
|
|||||||
|
<?php
|
||||||
|
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||||
|
|
||||||
|
/*
|
||||||
|
| -------------------------------------------------------------------------
|
||||||
|
| VERTICAL REGISTRY
|
||||||
|
| -------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| One entry per service area ("vertical") the salon offers. Adding a fourth
|
||||||
|
| vertical should be one entry here plus its content files — not edits
|
||||||
|
| scattered across the controller, the model and twenty views.
|
||||||
|
|
|
||||||
|
| STRANGLER NOTE
|
||||||
|
| --------------
|
||||||
|
| 'barber' and 'beauty' deliberately point their view_* keys at the dedicated
|
||||||
|
| files that already exist. Their rendered HTML is therefore byte-identical
|
||||||
|
| after this registry was introduced. Only 'massage' uses the generic
|
||||||
|
| parameterised views (pages/vertical-*.php). Once those are proven in
|
||||||
|
| production, barber/beauty can be repointed at the generic views and their
|
||||||
|
| eight dedicated files deleted — with a before/after HTML diff as the test.
|
||||||
|
|
|
||||||
|
| KEYS
|
||||||
|
| ----
|
||||||
|
| slug URL segment, services.service_type value, registry key.
|
||||||
|
| These three MUST agree; see below.
|
||||||
|
| enabled FALSE removes the vertical from routing entirely (404).
|
||||||
|
| public TRUE = appears as a tile on the home page. A vertical can
|
||||||
|
| be routable but not yet advertised — that is the launch
|
||||||
|
| switch.
|
||||||
|
| sort tile / listing order, ascending.
|
||||||
|
| label per-language display name, used for the home tile <h2>.
|
||||||
|
| heading the "- BEAUTY" text beside the logo in the header.
|
||||||
|
| category_slug service_categories.serv_cat_slug that this vertical's
|
||||||
|
| workers belong to. Informational: the runtime derives the
|
||||||
|
| worker set from the DB, never from this value.
|
||||||
|
|
|
||||||
|
| ONE SLUG ACROSS ALL LANGUAGES
|
||||||
|
| -----------------------------
|
||||||
|
| The language switcher rebuilds URLs by exploding $_SERVER['REQUEST_URI'] and
|
||||||
|
| reusing segment 2 verbatim (see *-header.php). A per-language slug would
|
||||||
|
| therefore produce a 404 the moment a visitor switched language. Do not add
|
||||||
|
| one. If a localised URL is ever needed, add an alias route pointing at the
|
||||||
|
| same canonical slug.
|
||||||
|
|
|
||||||
|
| Note also config.php permitted_uri_chars excludes æ/ø/å, so a Norwegian
|
||||||
|
| slug containing them would be rejected by CodeIgniter before routing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$config['verticals'] = array(
|
||||||
|
|
||||||
|
'barber' => array(
|
||||||
|
'slug' => 'barber',
|
||||||
|
'enabled' => TRUE,
|
||||||
|
'public' => TRUE,
|
||||||
|
'sort' => 10,
|
||||||
|
'category_slug' => 'cosmeric',
|
||||||
|
|
||||||
|
'label' => array('no' => 'BARBER', 'en' => 'BARBER', 'hu' => 'BARBER'),
|
||||||
|
'heading' => '- BARBER',
|
||||||
|
|
||||||
|
'title' => 'Studio Beve - Beauty & Barber Shop',
|
||||||
|
'og_site_name' => 'Studio Beve Barber',
|
||||||
|
'og_description' => 'Vippestylist, make up artist, PMU-artist',
|
||||||
|
'meta_description' => 'Skjeggtrimming, Barneklipp, Skjeggfarging, Herreklipp, Skinfade Herreklipp, Voks, Beard Trimming, Child Haircut, Beard Dying, Traditional Shave, Men\'s Haircut, Skinfade, Wax, herrefrisør, Trondheim, hårklipp, haircut, barber, barberer, Men\'s hairdresser',
|
||||||
|
|
||||||
|
'css' => 'barber.css',
|
||||||
|
'logo' => 'logo_gold.png',
|
||||||
|
'img_dir' => 'barber',
|
||||||
|
'map_img' => 'assets/img/barber/map.jpg',
|
||||||
|
|
||||||
|
'facebook' => 'https://www.facebook.com/studiobevebarber',
|
||||||
|
'instagram' => 'https://www.instagram.com/studio.beve.barber/',
|
||||||
|
|
||||||
|
'tile_class' => 'style2',
|
||||||
|
'tile_img' => 'assets/img/barber.jpg',
|
||||||
|
// The <img> in the home tile is only a size spacer; the visible art is
|
||||||
|
// the CSS .image:before background. Kept per-vertical so the existing
|
||||||
|
// tiles render exactly as before.
|
||||||
|
'tile_spacer' => 'assets/img/pic03.jpg',
|
||||||
|
|
||||||
|
// Strangler: existing dedicated files, untouched.
|
||||||
|
'skeleton' => 'barber',
|
||||||
|
'view_landing' => 'pages/barber',
|
||||||
|
'view_booking' => 'pages/barber-booking',
|
||||||
|
'view_finished' => 'pages/barber-booking-finished',
|
||||||
|
'view_error' => 'pages/barber-booking-error',
|
||||||
|
),
|
||||||
|
|
||||||
|
'beauty' => array(
|
||||||
|
'slug' => 'beauty',
|
||||||
|
'enabled' => TRUE,
|
||||||
|
'public' => TRUE,
|
||||||
|
'sort' => 20,
|
||||||
|
'category_slug' => 'cosmeric',
|
||||||
|
|
||||||
|
'label' => array('no' => 'BEAUTY', 'en' => 'BEAUTY', 'hu' => 'BEAUTY'),
|
||||||
|
'heading' => '- BEAUTY',
|
||||||
|
|
||||||
|
'title' => 'Studio Beve - Beauty',
|
||||||
|
'og_site_name' => 'Studio Beve',
|
||||||
|
'og_description' => 'Vippestylist, make up artist, PMU-artist',
|
||||||
|
'meta_description' => 'Voksing, Sminke, Vippeextensions, Pudderbryn, PMU-Tatovering, Øyenbrynstyling, Vippestyling, Powder Brows, permanent, PMU Makeup, Makeup, Wax, Eyelash Extension, Eyebrow styling, Eyelash Styling, Wedding makeup, Brow lamination, Lash dying, Brow forming, Henna dying, Lash lift, Naturlig sminke, Bryllupssminke, Laminering, Henna farging, Vippeløft, Forming av bryn, Farging av vipper, Trondheim',
|
||||||
|
|
||||||
|
'css' => 'beauty.css',
|
||||||
|
'logo' => 'logo.png',
|
||||||
|
'img_dir' => 'beauty',
|
||||||
|
'map_img' => 'assets/img/beauty/map.jpg',
|
||||||
|
|
||||||
|
'facebook' => 'https://www.facebook.com/studiobevebeauty',
|
||||||
|
'instagram' => 'https://www.instagram.com/studio.beve.beauty/',
|
||||||
|
|
||||||
|
'tile_class' => 'style1',
|
||||||
|
'tile_img' => 'assets/img/beauty.jpg',
|
||||||
|
'tile_spacer' => 'assets/img/pic09.jpg',
|
||||||
|
|
||||||
|
// Strangler: existing dedicated files, untouched.
|
||||||
|
'skeleton' => 'beauty',
|
||||||
|
'view_landing' => 'pages/beauty',
|
||||||
|
'view_booking' => 'pages/beauty-booking',
|
||||||
|
'view_finished' => 'pages/beauty-booking-finished',
|
||||||
|
'view_error' => 'pages/beauty-booking-error',
|
||||||
|
),
|
||||||
|
|
||||||
|
'massage' => array(
|
||||||
|
'slug' => 'massage',
|
||||||
|
'enabled' => TRUE,
|
||||||
|
// Launch switch: the tile CSS now supports three tiles, so massage is live.
|
||||||
|
'public' => TRUE,
|
||||||
|
'sort' => 30,
|
||||||
|
'category_slug' => 'massage',
|
||||||
|
// Row labels in grouped service lists drop the category prefix, so a
|
||||||
|
// heading of "Klassisk svensk massasje" is followed by "50 min" rather
|
||||||
|
// than the whole name again. barber/beauty omit this and are unchanged.
|
||||||
|
'strip_category_prefix' => TRUE,
|
||||||
|
// A guest books one massage at a time: selecting a treatment clears and
|
||||||
|
// disables the others. Enforced in the UI *and* in booking_process().
|
||||||
|
// barber/beauty omit this and keep multi-select.
|
||||||
|
'single_service_booking' => TRUE,
|
||||||
|
|
||||||
|
'label' => array('no' => 'MASSASJE', 'en' => 'MASSAGE', 'hu' => 'MASSZÁZS'),
|
||||||
|
'heading' => '- MASSAGE',
|
||||||
|
|
||||||
|
'title' => 'Studio Beve - Massage',
|
||||||
|
'og_site_name' => 'Studio Beve Massage',
|
||||||
|
'og_description' => 'Massasje, klassisk massasje, dyp vevsmassasje',
|
||||||
|
'meta_description' => 'Massasje, Klassisk massasje, Dypvevsmassasje, Ryggmassasje, Nakkemassasje, Idrettsmassasje, Avslappende massasje, Massage, Deep tissue massage, Sports massage, Relaxing massage, Back massage, Masszázs, Svédmasszázs, Frissítő masszázs, Trondheim',
|
||||||
|
|
||||||
|
'css' => 'massage.css',
|
||||||
|
'logo' => 'logo.png',
|
||||||
|
'img_dir' => 'massage',
|
||||||
|
'map_img' => 'assets/img/massage/map.jpg',
|
||||||
|
|
||||||
|
'facebook' => 'https://www.facebook.com/studiobevebeauty',
|
||||||
|
'instagram' => 'https://www.instagram.com/studio.beve.beauty/',
|
||||||
|
|
||||||
|
'tile_class' => 'style3',
|
||||||
|
'tile_img' => 'assets/img/massage.jpg',
|
||||||
|
'tile_spacer' => 'assets/img/pic03.jpg',
|
||||||
|
|
||||||
|
// The generic parameterised views.
|
||||||
|
'skeleton' => 'vertical',
|
||||||
|
'view_landing' => 'pages/vertical-landing',
|
||||||
|
'view_booking' => 'pages/vertical-booking',
|
||||||
|
'view_finished' => 'pages/vertical-booking-finished',
|
||||||
|
'view_error' => 'pages/vertical-booking-error',
|
||||||
|
),
|
||||||
|
|
||||||
|
);
|
||||||
@@ -298,8 +298,9 @@ class Admin extends CI_Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(isset($_POST['addNewService'])){
|
if(isset($_POST['addNewService'])){
|
||||||
|
$allowedServiceTypes = array('barber', 'beauty', 'massage');
|
||||||
$serviceArray = array(
|
$serviceArray = array(
|
||||||
'service_type' => $_POST['service_type'],
|
'service_type' => (isset($_POST['service_type']) && in_array($_POST['service_type'], $allowedServiceTypes, true)) ? $_POST['service_type'] : 'beauty',
|
||||||
'service_category_no' => $_POST['service_category_no'],
|
'service_category_no' => $_POST['service_category_no'],
|
||||||
'service_category_en' => $_POST['service_category_en'],
|
'service_category_en' => $_POST['service_category_en'],
|
||||||
'service_category_hu' => $_POST['service_category_hu'],
|
'service_category_hu' => $_POST['service_category_hu'],
|
||||||
@@ -320,8 +321,10 @@ class Admin extends CI_Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(isset($_POST['updateService'])){
|
if(isset($_POST['updateService'])){
|
||||||
|
$allowedServiceTypes = array('barber', 'beauty', 'massage');
|
||||||
|
$existingService = $this->Service_model->getServiceById($_POST['service_id']);
|
||||||
$serviceArray = array(
|
$serviceArray = array(
|
||||||
'service_type' => $_POST['service_type'],
|
'service_type' => (isset($_POST['service_type']) && in_array($_POST['service_type'], $allowedServiceTypes, true)) ? $_POST['service_type'] : ($existingService ? $existingService->service_type : 'beauty'),
|
||||||
'service_category_no' => $_POST['service_category_no'],
|
'service_category_no' => $_POST['service_category_no'],
|
||||||
'service_category_en' => $_POST['service_category_en'],
|
'service_category_en' => $_POST['service_category_en'],
|
||||||
'service_category_hu' => $_POST['service_category_hu'],
|
'service_category_hu' => $_POST['service_category_hu'],
|
||||||
@@ -542,6 +545,8 @@ class Admin extends CI_Controller {
|
|||||||
|
|
||||||
$data['serviceCategories'] = $this->Service_model->getAllServiceCategories();
|
$data['serviceCategories'] = $this->Service_model->getAllServiceCategories();
|
||||||
$data['selectedItem'] = $this->Service_model->getWorkerById($worker_id);
|
$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);
|
||||||
$this->load->view('admin/update-worker', $data);
|
$this->load->view('admin/update-worker', $data);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
@@ -597,11 +602,12 @@ class Admin extends CI_Controller {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// is_beauty / is_barber are no longer submitted by the form - the
|
||||||
|
// vertical is derived from service_category_id. Service_model
|
||||||
|
// keeps the legacy columns consistent on write.
|
||||||
$workerArray = array(
|
$workerArray = array(
|
||||||
'worker_name' => $_POST['worker_name'],
|
'worker_name' => $_POST['worker_name'],
|
||||||
'worker_info' => $_POST['worker_info'],
|
'worker_info' => $_POST['worker_info'],
|
||||||
'is_beauty' => $_POST['is_beauty'],
|
|
||||||
'is_barber' => $_POST['is_barber'],
|
|
||||||
'worker_profile_img' => $data['worker_img'],
|
'worker_profile_img' => $data['worker_img'],
|
||||||
'service_category_id' => $_POST['service_category_id'],
|
'service_category_id' => $_POST['service_category_id'],
|
||||||
'is_active' => $_POST['is_active']
|
'is_active' => $_POST['is_active']
|
||||||
@@ -615,8 +621,6 @@ class Admin extends CI_Controller {
|
|||||||
$workerArray = array(
|
$workerArray = array(
|
||||||
'worker_name' => $_POST['worker_name'],
|
'worker_name' => $_POST['worker_name'],
|
||||||
'worker_info' => $_POST['worker_info'],
|
'worker_info' => $_POST['worker_info'],
|
||||||
'is_beauty' => $_POST['is_beauty'],
|
|
||||||
'is_barber' => $_POST['is_barber'],
|
|
||||||
'service_category_id' => $_POST['service_category_id'],
|
'service_category_id' => $_POST['service_category_id'],
|
||||||
'is_active' => $_POST['is_active'],
|
'is_active' => $_POST['is_active'],
|
||||||
'google_calendar_id' => isset($_POST['google_calendar_id']) ? $_POST['google_calendar_id'] : '',
|
'google_calendar_id' => isset($_POST['google_calendar_id']) ? $_POST['google_calendar_id'] : '',
|
||||||
|
|||||||
@@ -49,6 +49,31 @@ class Pages extends CI_Controller {
|
|||||||
$this->load->view('pages/beauty', $data);
|
$this->load->view('pages/beauty', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic landing page for any registered vertical.
|
||||||
|
*
|
||||||
|
* barber() and beauty() above are kept as-is so their rendered HTML does
|
||||||
|
* not change; new verticals route here instead of gaining a method each.
|
||||||
|
*/
|
||||||
|
public function vertical($lang, $slug){
|
||||||
|
$this->load->helper('url');
|
||||||
|
$this->load->model('User_model');
|
||||||
|
$this->load->model('Service_model');
|
||||||
|
|
||||||
|
$vertical = vertical_get($slug);
|
||||||
|
if(!$vertical){
|
||||||
|
show_404();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data['pageTitle'] = '';
|
||||||
|
$data['selectedLang'] = vertical_lang($lang);
|
||||||
|
$data['vertical'] = $vertical;
|
||||||
|
$data['services'] = $this->Service_model->getAllServiceByServiceType($vertical['slug'], $data['selectedLang']);
|
||||||
|
|
||||||
|
$this->load->view($vertical['view_landing'], $data);
|
||||||
|
}
|
||||||
|
|
||||||
public function booking($lang, $subpage){
|
public function booking($lang, $subpage){
|
||||||
$this->load->helper('url');
|
$this->load->helper('url');
|
||||||
$this->load->model('User_model');
|
$this->load->model('User_model');
|
||||||
@@ -58,19 +83,20 @@ class Pages extends CI_Controller {
|
|||||||
$data['selectedLang'] = $lang;
|
$data['selectedLang'] = $lang;
|
||||||
$data['subpage'] = $subpage;
|
$data['subpage'] = $subpage;
|
||||||
|
|
||||||
|
// Whitelist the vertical through the registry. An unknown slug used to
|
||||||
|
// fall through the switch default to a bare redirect; now anything not
|
||||||
|
// registered and enabled is rejected the same way, in one place.
|
||||||
|
$vertical = vertical_get($subpage);
|
||||||
|
if(!$vertical){
|
||||||
|
header('Location:'.SITEURL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data['vertical'] = $vertical;
|
||||||
$data['services'] = $this->Service_model->getAllServiceByServiceType($subpage, $lang);
|
$data['services'] = $this->Service_model->getAllServiceByServiceType($subpage, $lang);
|
||||||
$data['workers'] = $this->Service_model->getActiveWorkers($subpage);
|
$data['workers'] = $this->Service_model->getActiveWorkers($subpage);
|
||||||
|
|
||||||
switch($subpage){
|
$this->load->view($vertical['view_booking'], $data);
|
||||||
case 'barber':
|
|
||||||
$this->load->view('pages/barber-booking', $data);
|
|
||||||
break;
|
|
||||||
case 'beauty':
|
|
||||||
$this->load->view('pages/beauty-booking', $data);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
header('Location:'.SITEURL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function booking_finished($lang, $subpage){
|
public function booking_finished($lang, $subpage){
|
||||||
@@ -80,16 +106,16 @@ class Pages extends CI_Controller {
|
|||||||
$data['pageTitle'] = '';
|
$data['pageTitle'] = '';
|
||||||
$data['selectedLang'] = $lang;
|
$data['selectedLang'] = $lang;
|
||||||
|
|
||||||
switch($subpage){
|
$vertical = vertical_get($subpage);
|
||||||
case 'barber':
|
if(!$vertical){
|
||||||
$this->load->view('pages/barber-booking-finished', $data);
|
|
||||||
break;
|
|
||||||
case 'beauty':
|
|
||||||
$this->load->view('pages/beauty-booking-finished', $data);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
header('Location:'.SITEURL);
|
header('Location:'.SITEURL);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$data['vertical'] = $vertical;
|
||||||
|
$data['subpage'] = $subpage;
|
||||||
|
|
||||||
|
$this->load->view($vertical['view_finished'], $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function email_verification(){
|
public function email_verification(){
|
||||||
@@ -284,24 +310,25 @@ class Pages extends CI_Controller {
|
|||||||
private function _booking_error($errorCode, $statusCode = 409){
|
private function _booking_error($errorCode, $statusCode = 409){
|
||||||
$this->load->helper('url');
|
$this->load->helper('url');
|
||||||
|
|
||||||
$lang = isset($_POST['lang']) && in_array($_POST['lang'], array('no', 'en', 'hu')) ? $_POST['lang'] : 'en';
|
$lang = vertical_lang(isset($_POST['lang']) ? $_POST['lang'] : '');
|
||||||
$subpage = isset($_POST['subpage']) && $_POST['subpage'] != '' ? $_POST['subpage'] : 'barber';
|
|
||||||
|
// vertical_get() doubles as the whitelist for the posted subpage:
|
||||||
|
// anything unregistered falls back to barber, as before.
|
||||||
|
$vertical = vertical_get(isset($_POST['subpage']) ? $_POST['subpage'] : '');
|
||||||
|
if(!$vertical){
|
||||||
|
$vertical = vertical_get('barber');
|
||||||
|
}
|
||||||
|
|
||||||
$data = array(
|
$data = array(
|
||||||
'pageTitle' => '',
|
'pageTitle' => '',
|
||||||
'selectedLang' => $lang,
|
'selectedLang' => $lang,
|
||||||
'subpage' => $subpage,
|
'subpage' => $vertical['slug'],
|
||||||
|
'vertical' => $vertical,
|
||||||
'bookingErrorCode' => $errorCode
|
'bookingErrorCode' => $errorCode
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->output->set_status_header($statusCode);
|
$this->output->set_status_header($statusCode);
|
||||||
|
$this->load->view($vertical['view_error'], $data);
|
||||||
if($subpage == 'beauty'){
|
|
||||||
$this->load->view('pages/beauty-booking-error', $data);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
$this->load->view('pages/barber-booking-error', $data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function booking_process(){
|
public function booking_process(){
|
||||||
@@ -379,8 +406,40 @@ class Pages extends CI_Controller {
|
|||||||
|
|
||||||
$bookingDate = $bookingArray['booking_date'];
|
$bookingDate = $bookingArray['booking_date'];
|
||||||
$bookingTime = $bookingArray['booking_start_time'];
|
$bookingTime = $bookingArray['booking_start_time'];
|
||||||
$weekday = date('w', strtotime($bookingDate));
|
|
||||||
$schedule = $this->Service_model->getWorkerScheduleByDay($bookingArray['worker_id'], $weekday);
|
// Category match: the worker must actually perform EVERY selected service.
|
||||||
|
// Mirrors the guard in manage_booking_process(); server-side equivalent of the
|
||||||
|
// client-side mutual exclusion, so a crafted or replayed POST cannot book a
|
||||||
|
// worker for another vertical's services.
|
||||||
|
$submittedWorker = $this->Service_model->getWorkerById($bookingArray['worker_id']);
|
||||||
|
if (!$submittedWorker) {
|
||||||
|
$this->_booking_error('worker_unavailable', 403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (empty($selectedServiceArray)) {
|
||||||
|
$this->_booking_error('no_service', 400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foreach ($selectedServiceArray as $selectedServiceId) {
|
||||||
|
$selectedService = $this->Service_model->getServiceById($selectedServiceId);
|
||||||
|
if (!$selectedService || $selectedService->service_category_id != $submittedWorker->service_category_id) {
|
||||||
|
$this->_booking_error('category_mismatch', 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
|
||||||
|
// client-supplied.
|
||||||
|
$firstSelectedService = $this->Service_model->getServiceById($selectedServiceArray[0]);
|
||||||
|
$bookingVertical = $firstSelectedService ? vertical_get($firstSelectedService->service_type) : NULL;
|
||||||
|
if (!empty($bookingVertical['single_service_booking']) && count($selectedServiceArray) > 1) {
|
||||||
|
$this->_booking_error('single_service_only', 400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$schedule = $this->Service_model->getWorkerScheduleForDate($bookingArray['worker_id'], $bookingDate);
|
||||||
|
|
||||||
if (!$schedule) {
|
if (!$schedule) {
|
||||||
$this->_booking_error('worker_unavailable', 403);
|
$this->_booking_error('worker_unavailable', 403);
|
||||||
@@ -392,7 +451,7 @@ class Pages extends CI_Controller {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->Service_model->isWorkerAvailableThisWeek($bookingArray['worker_id'], $bookingDate)) {
|
if ($schedule->source === 'schedule' && !$this->Service_model->isWorkerAvailableThisWeek($bookingArray['worker_id'], $bookingDate)) {
|
||||||
$this->_booking_error('alternate_week', 403);
|
$this->_booking_error('alternate_week', 403);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -755,23 +814,37 @@ class Pages extends CI_Controller {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine booking type from services
|
// Determine booking type from services. Scan until one resolves rather
|
||||||
|
// than trusting services[0]: if that single service has since been
|
||||||
|
// hard-deleted, the guest's manage page would silently render with the
|
||||||
|
// wrong vertical's branding.
|
||||||
$serviceIds = unserialize($booking->service_ids);
|
$serviceIds = unserialize($booking->service_ids);
|
||||||
$subpage = 'barber';
|
$subpage = 'barber';
|
||||||
if(is_array($serviceIds) && !empty($serviceIds)){
|
if(is_array($serviceIds)){
|
||||||
$firstService = $this->Service_model->getServiceById($serviceIds[0]);
|
foreach($serviceIds as $serviceIdItem){
|
||||||
if($firstService){
|
$resolvedService = $this->Service_model->getServiceById($serviceIdItem);
|
||||||
$subpage = $firstService->service_type;
|
if($resolvedService && $resolvedService->service_type !== ''){
|
||||||
|
$subpage = $resolvedService->service_type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$now = new DateTime('now', new DateTimeZone('Europe/Oslo'));
|
$now = new DateTime('now', new DateTimeZone('Europe/Oslo'));
|
||||||
$appointmentDT = new DateTime($booking->booking_date.' '.$booking->booking_start_time, new DateTimeZone('Europe/Oslo'));
|
$appointmentDT = new DateTime($booking->booking_date.' '.$booking->booking_start_time, new DateTimeZone('Europe/Oslo'));
|
||||||
|
|
||||||
|
// A booking's vertical is derived from its services, so an unregistered
|
||||||
|
// or stale service_type must still render something: fall back to barber.
|
||||||
|
$vertical = vertical_get($subpage);
|
||||||
|
if(!$vertical){
|
||||||
|
$vertical = vertical_get('barber');
|
||||||
|
}
|
||||||
|
|
||||||
$data['token'] = $token;
|
$data['token'] = $token;
|
||||||
$data['booking'] = $booking;
|
$data['booking'] = $booking;
|
||||||
$data['selectedLang'] = $lang;
|
$data['selectedLang'] = $lang;
|
||||||
$data['subpage'] = $subpage;
|
$data['subpage'] = $vertical['slug'];
|
||||||
|
$data['vertical'] = $vertical;
|
||||||
$data['pageTitle'] = '';
|
$data['pageTitle'] = '';
|
||||||
$data['status'] = 'ok';
|
$data['status'] = 'ok';
|
||||||
|
|
||||||
@@ -863,8 +936,7 @@ class Pages extends CI_Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Schedule check
|
// Schedule check
|
||||||
$weekday = date('w', strtotime($newBookingDate));
|
$schedule = $this->Service_model->getWorkerScheduleForDate($newWorkerId, $newBookingDate);
|
||||||
$schedule = $this->Service_model->getWorkerScheduleByDay($newWorkerId, $weekday);
|
|
||||||
if(!$schedule){
|
if(!$schedule){
|
||||||
$this->output->set_status_header(403)->set_content_type('application/json')
|
$this->output->set_status_header(403)->set_content_type('application/json')
|
||||||
->set_output(json_encode(['error' => 'Worker is not available on this day.']));
|
->set_output(json_encode(['error' => 'Worker is not available on this day.']));
|
||||||
|
|||||||
@@ -0,0 +1,239 @@
|
|||||||
|
<?php
|
||||||
|
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vertical registry helper.
|
||||||
|
*
|
||||||
|
* Thin accessors over application/config/verticals.php so controllers and
|
||||||
|
* views never poke at the raw config array. Every function is safe to call
|
||||||
|
* with untrusted input — vertical_get() returns NULL for anything that is not
|
||||||
|
* a known, enabled vertical, which is what makes it usable as a whitelist for
|
||||||
|
* $_POST['subpage'] and for route segments.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( ! function_exists('vertical_all'))
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Every registered vertical, including disabled ones, keyed by slug.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function vertical_all()
|
||||||
|
{
|
||||||
|
$CI =& get_instance();
|
||||||
|
$CI->config->load('verticals', FALSE, TRUE);
|
||||||
|
$verticals = $CI->config->item('verticals');
|
||||||
|
|
||||||
|
return is_array($verticals) ? $verticals : array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! function_exists('vertical_get'))
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* One vertical by slug, or NULL when the slug is unknown or disabled.
|
||||||
|
*
|
||||||
|
* Use this as the whitelist for any user-supplied vertical value.
|
||||||
|
*
|
||||||
|
* @param string $slug
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
function vertical_get($slug)
|
||||||
|
{
|
||||||
|
if ( ! is_string($slug) || $slug === '')
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$verticals = vertical_all();
|
||||||
|
|
||||||
|
if ( ! isset($verticals[$slug]))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($verticals[$slug]['enabled']))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $verticals[$slug];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! function_exists('vertical_exists'))
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param string $slug
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function vertical_exists($slug)
|
||||||
|
{
|
||||||
|
return vertical_get($slug) !== NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! function_exists('vertical_slugs'))
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Slugs of every enabled vertical. Suitable for in_array() checks and for
|
||||||
|
* building the admin service_type dropdown.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function vertical_slugs()
|
||||||
|
{
|
||||||
|
$slugs = array();
|
||||||
|
|
||||||
|
foreach (vertical_all() as $slug => $vertical)
|
||||||
|
{
|
||||||
|
if ( ! empty($vertical['enabled']))
|
||||||
|
{
|
||||||
|
$slugs[] = $slug;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $slugs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! function_exists('vertical_public'))
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Enabled verticals flagged public, ordered by 'sort'. This is what the
|
||||||
|
* home page tiles iterate over — flipping 'public' is the launch switch.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function vertical_public()
|
||||||
|
{
|
||||||
|
$public = array();
|
||||||
|
|
||||||
|
foreach (vertical_all() as $slug => $vertical)
|
||||||
|
{
|
||||||
|
if ( ! empty($vertical['enabled']) && ! empty($vertical['public']))
|
||||||
|
{
|
||||||
|
$public[$slug] = $vertical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uasort($public, 'vertical_sort_compare');
|
||||||
|
|
||||||
|
return $public;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! function_exists('vertical_sort_compare'))
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* uasort() callback. Named rather than a closure so this helper stays
|
||||||
|
* compatible with the PHP version the live host runs.
|
||||||
|
*
|
||||||
|
* @param array $a
|
||||||
|
* @param array $b
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
function vertical_sort_compare($a, $b)
|
||||||
|
{
|
||||||
|
$sa = isset($a['sort']) ? (int) $a['sort'] : 0;
|
||||||
|
$sb = isset($b['sort']) ? (int) $b['sort'] : 0;
|
||||||
|
|
||||||
|
if ($sa === $sb)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($sa < $sb) ? -1 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! function_exists('vertical_label'))
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display label for a vertical in the given language, falling back to
|
||||||
|
* English and then to the uppercased slug.
|
||||||
|
*
|
||||||
|
* @param array $vertical
|
||||||
|
* @param string $lang
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function vertical_label($vertical, $lang)
|
||||||
|
{
|
||||||
|
if (isset($vertical['label'][$lang]))
|
||||||
|
{
|
||||||
|
return $vertical['label'][$lang];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($vertical['label']['en']))
|
||||||
|
{
|
||||||
|
return $vertical['label']['en'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return isset($vertical['slug']) ? strtoupper($vertical['slug']) : '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! function_exists('vertical_lang'))
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Whitelist a language segment. The site serves no/en/hu; anything else
|
||||||
|
* falls back to English, matching the existing per-view $langArray checks.
|
||||||
|
*
|
||||||
|
* @param string $lang
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function vertical_lang($lang)
|
||||||
|
{
|
||||||
|
$allowed = array('no', 'en', 'hu');
|
||||||
|
|
||||||
|
return (is_string($lang) && in_array($lang, $allowed, TRUE)) ? $lang : 'en';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! function_exists('vertical_service_label'))
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display label for a service in a list that is ALREADY grouped under its
|
||||||
|
* category heading.
|
||||||
|
*
|
||||||
|
* services.service_name has to stay self-describing - the confirmation email
|
||||||
|
* and the admin lists render it with no category around it. But in the
|
||||||
|
* booking form, the manage-booking form and the landing-page price list the
|
||||||
|
* category heading sits directly above the row, so repeating it makes every
|
||||||
|
* row wrap and the list read as cramped:
|
||||||
|
*
|
||||||
|
* [Studio Beve Signature - individuelt tilpasset massasje]
|
||||||
|
* Studio Beve Signature - individuelt tilpasset massasje - 50 min
|
||||||
|
*
|
||||||
|
* Opt in per vertical via 'strip_category_prefix' so barber and beauty keep
|
||||||
|
* rendering exactly as before.
|
||||||
|
*
|
||||||
|
* @param array $vertical registry row (may be NULL or missing the key)
|
||||||
|
* @param object $serviceItem needs ->service_name and ->service_category
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function vertical_service_label($vertical, $serviceItem)
|
||||||
|
{
|
||||||
|
$name = isset($serviceItem->service_name) ? $serviceItem->service_name : '';
|
||||||
|
|
||||||
|
if (empty($vertical['strip_category_prefix']))
|
||||||
|
{
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
$category = isset($serviceItem->service_category) ? $serviceItem->service_category : '';
|
||||||
|
|
||||||
|
if ($category === '' OR strpos($name, $category) !== 0)
|
||||||
|
{
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The /u modifier matters: the separator is an en dash, and a byte-wise
|
||||||
|
// trim() would only mangle it.
|
||||||
|
$stripped = substr($name, strlen($category));
|
||||||
|
$stripped = preg_replace('/^[\s\-–—]+/u', '', $stripped);
|
||||||
|
$stripped = trim($stripped);
|
||||||
|
|
||||||
|
return ($stripped !== '') ? $stripped : $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -63,8 +63,70 @@ class Service_model extends CI_Model {
|
|||||||
$this->db->update('service_categories', $serviceCategoryArray);
|
$this->db->update('service_categories', $serviceCategoryArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The verticals (service_type values) a service category covers.
|
||||||
|
*
|
||||||
|
* This is the single source of truth for "what does this worker do".
|
||||||
|
*
|
||||||
|
* @param int $service_category_id
|
||||||
|
* @return array e.g. array('barber', 'beauty')
|
||||||
|
*/
|
||||||
|
public function getVerticalsForCategory($service_category_id){
|
||||||
|
$this->load->database();
|
||||||
|
$query = $this->db->query('
|
||||||
|
SELECT DISTINCT service_type
|
||||||
|
FROM services
|
||||||
|
WHERE service_category_id = ?
|
||||||
|
AND is_deleted != "1"
|
||||||
|
ORDER BY service_type ASC;', array($service_category_id));
|
||||||
|
|
||||||
|
$types = array();
|
||||||
|
foreach($query->result() as $row){
|
||||||
|
$types[] = $row->service_type;
|
||||||
|
}
|
||||||
|
return $types;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The verticals a given worker covers, derived from their category.
|
||||||
|
*
|
||||||
|
* @param int $worker_id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getVerticalsForWorker($worker_id){
|
||||||
|
$this->load->database();
|
||||||
|
$worker = $this->getWorkerById($worker_id);
|
||||||
|
|
||||||
|
if(!$worker){
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getVerticalsForCategory($worker->service_category_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keep the legacy is_beauty / is_barber columns consistent with the
|
||||||
|
* category. NOTHING reads them any more - the vertical is derived (see
|
||||||
|
* getActiveWorkers). They are still NOT NULL, and writing a correct value
|
||||||
|
* means a code rollback cannot strand a newly created worker as invisible.
|
||||||
|
* Derived here rather than trusted from $_POST so the two cannot drift.
|
||||||
|
*
|
||||||
|
* @param array $workerArray by reference; keys are added
|
||||||
|
* @param int $service_category_id
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function _applyLegacyVerticalFlags(&$workerArray, $service_category_id){
|
||||||
|
$verticals = $this->getVerticalsForCategory($service_category_id);
|
||||||
|
|
||||||
|
$workerArray['is_beauty'] = in_array('beauty', $verticals, TRUE) ? 1 : 0;
|
||||||
|
$workerArray['is_barber'] = in_array('barber', $verticals, TRUE) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
public function createWorker($workerArray){
|
public function createWorker($workerArray){
|
||||||
$this->load->database();
|
$this->load->database();
|
||||||
|
|
||||||
|
$this->_applyLegacyVerticalFlags($workerArray, $workerArray['service_category_id']);
|
||||||
|
|
||||||
$query = $this->db->query('INSERT INTO workers (
|
$query = $this->db->query('INSERT INTO workers (
|
||||||
worker_name,
|
worker_name,
|
||||||
worker_profile_img,
|
worker_profile_img,
|
||||||
@@ -84,6 +146,13 @@ class Service_model extends CI_Model {
|
|||||||
|
|
||||||
public function updateWorker($worker_id, $workerArray){
|
public function updateWorker($worker_id, $workerArray){
|
||||||
$this->load->database();
|
$this->load->database();
|
||||||
|
|
||||||
|
// Re-derive the legacy flags whenever the category is being written,
|
||||||
|
// so moving a worker between categories cannot leave them stale.
|
||||||
|
if(isset($workerArray['service_category_id'])){
|
||||||
|
$this->_applyLegacyVerticalFlags($workerArray, $workerArray['service_category_id']);
|
||||||
|
}
|
||||||
|
|
||||||
$this->db->where('worker_id', $worker_id);
|
$this->db->where('worker_id', $worker_id);
|
||||||
$this->db->update('workers', $workerArray);
|
$this->db->update('workers', $workerArray);
|
||||||
}
|
}
|
||||||
@@ -206,7 +275,28 @@ class Service_model extends CI_Model {
|
|||||||
|
|
||||||
public function getAllWorkers(){
|
public function getAllWorkers(){
|
||||||
$this->load->database();
|
$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" ORDER BY worker_name ASC;');
|
|
||||||
|
// LEFT JOIN, not INNER: with an inner join a worker whose category row
|
||||||
|
// is missing or soft-deleted vanishes from the admin list entirely
|
||||||
|
// rather than showing up as broken. Silent disappearance is worse.
|
||||||
|
//
|
||||||
|
// derived_verticals is computed here (one subquery, not N+1) so the
|
||||||
|
// list can show what a worker actually does without consulting the
|
||||||
|
// legacy is_barber / is_beauty columns.
|
||||||
|
$query = $this->db->query('
|
||||||
|
SELECT w.*,
|
||||||
|
sc.serv_cat_name,
|
||||||
|
sc.serv_cat_slug,
|
||||||
|
(SELECT GROUP_CONCAT(DISTINCT s.service_type ORDER BY s.service_type SEPARATOR ", ")
|
||||||
|
FROM services s
|
||||||
|
WHERE s.service_category_id = w.service_category_id
|
||||||
|
AND s.is_deleted != "1") AS derived_verticals
|
||||||
|
FROM workers w
|
||||||
|
LEFT JOIN service_categories sc
|
||||||
|
ON sc.service_category_id = w.service_category_id
|
||||||
|
WHERE w.is_deleted != "1"
|
||||||
|
ORDER BY w.worker_name ASC;');
|
||||||
|
|
||||||
return $query->result();
|
return $query->result();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,21 +306,52 @@ class Service_model extends CI_Model {
|
|||||||
return $query->result();
|
return $query->result();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Active workers, optionally restricted to one vertical.
|
||||||
|
*
|
||||||
|
* The vertical is DERIVED from the data that actually governs booking: a
|
||||||
|
* worker performs a vertical iff at least one live service of that
|
||||||
|
* service_type shares the worker's service_category_id.
|
||||||
|
*
|
||||||
|
* This replaces the old workers.is_barber / workers.is_beauty flags, which
|
||||||
|
* were a hand-maintained cache of exactly this fact and free to drift from
|
||||||
|
* it. Verified against production data before the switch: the derived set
|
||||||
|
* reproduced the stored flags exactly, for every worker, in both verticals.
|
||||||
|
* A new vertical therefore needs no schema change and no new flag column.
|
||||||
|
*
|
||||||
|
* Also removes the last string-concatenated WHERE fragment in this model -
|
||||||
|
* the obvious "fix" for a third vertical was ' AND is_'.$subpage.' = "1"',
|
||||||
|
* which would have turned this into an injection sink reachable from an
|
||||||
|
* unauthenticated POST.
|
||||||
|
*
|
||||||
|
* @param string $subpage vertical slug, or '' for every active worker
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
public function getActiveWorkers($subpage = ''){
|
public function getActiveWorkers($subpage = ''){
|
||||||
$this->load->database();
|
$this->load->database();
|
||||||
$subpageString = '';
|
|
||||||
|
|
||||||
if($subpage == 'beauty'){
|
// No-argument callers (Admin bookings filter, booking calendar) want
|
||||||
$subpageString = ' AND is_beauty = "1"';
|
// every active worker regardless of vertical. Preserve that exactly.
|
||||||
}
|
if($subpage === '' || $subpage === NULL){
|
||||||
else if($subpage == 'barber'){
|
$query = $this->db->query('SELECT * FROM workers WHERE is_active = "1" AND is_deleted != "1" ORDER BY worker_name ASC;');
|
||||||
$subpageString = ' AND is_barber = "1"';
|
return $query->result();
|
||||||
}
|
|
||||||
else{
|
|
||||||
$subpageString = '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = $this->db->query('SELECT * FROM workers WHERE is_active = "1" '.$subpageString.' AND is_deleted != "1" ORDER BY worker_name ASC;');
|
// EXISTS rather than JOIN + DISTINCT: a worker with several matching
|
||||||
|
// services must still appear once, and workers.worker_info is TEXT,
|
||||||
|
// which DISTINCT would have to de-duplicate needlessly.
|
||||||
|
$query = $this->db->query('
|
||||||
|
SELECT * FROM workers w
|
||||||
|
WHERE w.is_active = "1"
|
||||||
|
AND w.is_deleted != "1"
|
||||||
|
AND EXISTS (
|
||||||
|
SELECT 1 FROM services s
|
||||||
|
WHERE s.service_category_id = w.service_category_id
|
||||||
|
AND s.service_type = ?
|
||||||
|
AND s.is_deleted != "1"
|
||||||
|
)
|
||||||
|
ORDER BY w.worker_name ASC;', array($subpage));
|
||||||
|
|
||||||
return $query->result();
|
return $query->result();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,6 +376,20 @@ class Service_model extends CI_Model {
|
|||||||
$services = array();
|
$services = array();
|
||||||
foreach($servicesArray as $servicesArrayItem){
|
foreach($servicesArray as $servicesArrayItem){
|
||||||
$selectedService = $this->Service_model->getServiceById($servicesArrayItem);
|
$selectedService = $this->Service_model->getServiceById($servicesArrayItem);
|
||||||
|
|
||||||
|
// A hard-deleted service leaves older bookings pointing at a
|
||||||
|
// row that no longer exists. Render a visible placeholder
|
||||||
|
// rather than dereferencing null and blanking the row.
|
||||||
|
if(!$selectedService){
|
||||||
|
$services[] = (object)array(
|
||||||
|
'service_type' => '',
|
||||||
|
'service_name' => '[torolt szolgaltatas #'.$servicesArrayItem.']',
|
||||||
|
'service_price' => 0,
|
||||||
|
'service_time' => '00:00:00'
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$services[] = (object)array(
|
$services[] = (object)array(
|
||||||
'service_type' => $selectedService->service_type,
|
'service_type' => $selectedService->service_type,
|
||||||
'service_name' => $selectedService->service_name_hu,
|
'service_name' => $selectedService->service_name_hu,
|
||||||
@@ -299,6 +434,20 @@ class Service_model extends CI_Model {
|
|||||||
$services = array();
|
$services = array();
|
||||||
foreach($servicesArray as $servicesArrayItem){
|
foreach($servicesArray as $servicesArrayItem){
|
||||||
$selectedService = $this->Service_model->getServiceById($servicesArrayItem);
|
$selectedService = $this->Service_model->getServiceById($servicesArrayItem);
|
||||||
|
|
||||||
|
// A hard-deleted service leaves older bookings pointing at a
|
||||||
|
// row that no longer exists. Render a visible placeholder
|
||||||
|
// rather than dereferencing null and blanking the row.
|
||||||
|
if(!$selectedService){
|
||||||
|
$services[] = (object)array(
|
||||||
|
'service_type' => '',
|
||||||
|
'service_name' => '[torolt szolgaltatas #'.$servicesArrayItem.']',
|
||||||
|
'service_price' => 0,
|
||||||
|
'service_time' => '00:00:00'
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$services[] = (object)array(
|
$services[] = (object)array(
|
||||||
'service_type' => $selectedService->service_type,
|
'service_type' => $selectedService->service_type,
|
||||||
'service_name' => $selectedService->service_name_hu,
|
'service_name' => $selectedService->service_name_hu,
|
||||||
@@ -343,6 +492,20 @@ class Service_model extends CI_Model {
|
|||||||
$services = array();
|
$services = array();
|
||||||
foreach($servicesArray as $servicesArrayItem){
|
foreach($servicesArray as $servicesArrayItem){
|
||||||
$selectedService = $this->Service_model->getServiceById($servicesArrayItem);
|
$selectedService = $this->Service_model->getServiceById($servicesArrayItem);
|
||||||
|
|
||||||
|
// A hard-deleted service leaves older bookings pointing at a
|
||||||
|
// row that no longer exists. Render a visible placeholder
|
||||||
|
// rather than dereferencing null and blanking the row.
|
||||||
|
if(!$selectedService){
|
||||||
|
$services[] = (object)array(
|
||||||
|
'service_type' => '',
|
||||||
|
'service_name' => '[torolt szolgaltatas #'.$servicesArrayItem.']',
|
||||||
|
'service_price' => 0,
|
||||||
|
'service_time' => '00:00:00'
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$services[] = (object)array(
|
$services[] = (object)array(
|
||||||
'service_type' => $selectedService->service_type,
|
'service_type' => $selectedService->service_type,
|
||||||
'service_name' => $selectedService->service_name_hu,
|
'service_name' => $selectedService->service_name_hu,
|
||||||
@@ -796,6 +959,68 @@ class Service_model extends CI_Model {
|
|||||||
return $query->row(); // null if no row
|
return $query->row(); // null if no row
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date-aware schedule lookup. Mirrors the resolution order inside
|
||||||
|
* getAvailableTimes() exactly: an override for the date wins outright,
|
||||||
|
* otherwise fall back to worker_schedule honouring is_alternate_week.
|
||||||
|
*
|
||||||
|
* getWorkerScheduleByDay() above ignores both overrides and alternate
|
||||||
|
* weeks, so using it as a booking guard rejects slots the availability
|
||||||
|
* UI legitimately offered. Prefer this method for guards.
|
||||||
|
*
|
||||||
|
* @return object|null ->start_time, ->end_time, ->source ('override'|'schedule')
|
||||||
|
*/
|
||||||
|
public function getWorkerScheduleForDate($worker_id, $selectedDate) {
|
||||||
|
$this->load->database();
|
||||||
|
|
||||||
|
$overrideQuery = $this->db->query("
|
||||||
|
SELECT * FROM worker_schedule_overrides
|
||||||
|
WHERE worker_id = ? AND date = ?
|
||||||
|
LIMIT 1
|
||||||
|
", array($worker_id, $selectedDate));
|
||||||
|
|
||||||
|
if ($overrideQuery->num_rows() > 0) {
|
||||||
|
$override = $overrideQuery->row();
|
||||||
|
|
||||||
|
if ($override->is_day_off) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if ($override->start_time === null || $override->end_time === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (object) array(
|
||||||
|
'start_time' => $override->start_time,
|
||||||
|
'end_time' => $override->end_time,
|
||||||
|
'is_alternate_week' => 0,
|
||||||
|
'source' => 'override',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$weekday = date('w', strtotime($selectedDate));
|
||||||
|
$weekNumber = date('W', strtotime($selectedDate));
|
||||||
|
$isOddWeek = $weekNumber % 2 !== 0;
|
||||||
|
|
||||||
|
$scheduleQuery = $this->db->query("
|
||||||
|
SELECT * FROM worker_schedule
|
||||||
|
WHERE worker_id = ?
|
||||||
|
AND weekday = ?
|
||||||
|
AND (
|
||||||
|
is_alternate_week = 0
|
||||||
|
OR (is_alternate_week = 1 AND " . ($isOddWeek ? "1" : "0") . ")
|
||||||
|
)
|
||||||
|
LIMIT 1
|
||||||
|
", array($worker_id, $weekday));
|
||||||
|
|
||||||
|
if ($scheduleQuery->num_rows() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$schedule = $scheduleQuery->row();
|
||||||
|
$schedule->source = 'schedule';
|
||||||
|
return $schedule;
|
||||||
|
}
|
||||||
|
|
||||||
public function isEvenWeek($date) {
|
public function isEvenWeek($date) {
|
||||||
return ((int)date('W', strtotime($date)) % 2) === 0;
|
return ((int)date('W', strtotime($date)) % 2) === 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<select class="formDropdownBox" style="padding:0;" name="service_type">
|
<select class="formDropdownBox" style="padding:0;" name="service_type">
|
||||||
<option value="beauty" selected>beauty</option>
|
<option value="beauty" selected>beauty</option>
|
||||||
<option value="barber">barber</option>
|
<option value="barber">barber</option>
|
||||||
|
<option value="massage">massage</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="formRow">
|
<div class="formRow">
|
||||||
@@ -59,7 +60,7 @@
|
|||||||
<?php
|
<?php
|
||||||
if(!empty($serviceCategories)){
|
if(!empty($serviceCategories)){
|
||||||
foreach($serviceCategories as $serviceCategoryItem){
|
foreach($serviceCategories as $serviceCategoryItem){
|
||||||
echo '<option value="'.$serviceCategoryItem->service_category_id.'" selected>'.$serviceCategoryItem->serv_cat_name.'</option>';
|
echo '<option value="'.$serviceCategoryItem->service_category_id.'">'.$serviceCategoryItem->serv_cat_name.'</option>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -22,18 +22,11 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="formRow">
|
<div class="formRow">
|
||||||
<label class="formTitle">Beauty</label>
|
<label class="formTitle">Vertikálok</label>
|
||||||
<select class="formDropdownBox" style="padding:0;" name="is_beauty">
|
<div class="formInputBox" style="border:0;padding-left:0;font-size:11px;color:#888;">
|
||||||
<option value="1" selected>igen</option>
|
A dolgozó vertikáljait (barber / beauty / massage) az alább választott
|
||||||
<option value="0">nem</option>
|
szolgáltatás kategória határozza meg - nem kell külön beállítani.
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="formRow">
|
|
||||||
<label class="formTitle">Barber</label>
|
|
||||||
<select class="formDropdownBox" style="padding:0;" name="is_barber">
|
|
||||||
<option value="1" selected>igen</option>
|
|
||||||
<option value="0">nem</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="formRow">
|
<div class="formRow">
|
||||||
<label class="formTitle">Szolgáltatás kategória</label>
|
<label class="formTitle">Szolgáltatás kategória</label>
|
||||||
@@ -41,7 +34,7 @@
|
|||||||
<?php
|
<?php
|
||||||
if(!empty($serviceCategories)){
|
if(!empty($serviceCategories)){
|
||||||
foreach($serviceCategories as $serviceCategoryItem){
|
foreach($serviceCategories as $serviceCategoryItem){
|
||||||
echo '<option value="'.$serviceCategoryItem->service_category_id.'" selected>'.$serviceCategoryItem->serv_cat_name.'</option>';
|
echo '<option value="'.$serviceCategoryItem->service_category_id.'">'.$serviceCategoryItem->serv_cat_name.'</option>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<select class="formDropdownBox" style="padding:0;" name="service_type">
|
<select class="formDropdownBox" style="padding:0;" name="service_type">
|
||||||
<option value="beauty" <?php echo $selectedItem->service_type=='beauty'?'selected':'';?>>beauty</option>
|
<option value="beauty" <?php echo $selectedItem->service_type=='beauty'?'selected':'';?>>beauty</option>
|
||||||
<option value="barber" <?php echo $selectedItem->service_type=='barber'?'selected':'';?>>barber</option>
|
<option value="barber" <?php echo $selectedItem->service_type=='barber'?'selected':'';?>>barber</option>
|
||||||
|
<option value="massage" <?php echo $selectedItem->service_type=='massage'?'selected':'';?>>massage</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="formRow">
|
<div class="formRow">
|
||||||
|
|||||||
@@ -18,18 +18,18 @@
|
|||||||
<input type="text" class="formInputBox" name="worker_info" value="<?php echo htmlspecialchars($selectedItem->worker_info, ENT_QUOTES, 'UTF-8');?>">
|
<input type="text" class="formInputBox" name="worker_info" value="<?php echo htmlspecialchars($selectedItem->worker_info, ENT_QUOTES, 'UTF-8');?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="formRow">
|
<div class="formRow">
|
||||||
<label class="formTitle">Beauty</label>
|
<label class="formTitle">Vertikálok</label>
|
||||||
<select class="formDropdownBox" style="padding:0;" name="is_beauty">
|
<div class="formInputBox" style="border:0;padding-left:0;">
|
||||||
<option value="1" <?php echo $selectedItem->is_beauty?'selected':'';?>>igen</option>
|
<?php
|
||||||
<option value="0" <?php echo !$selectedItem->is_beauty?'selected':'';?>>nem</option>
|
$workerVerticals = isset($workerVerticals) ? $workerVerticals : array();
|
||||||
</select>
|
echo $workerVerticals
|
||||||
|
? htmlspecialchars(implode(', ', $workerVerticals), ENT_QUOTES, 'UTF-8')
|
||||||
|
: '<span style="color:#b00;">nincs szolgáltatás ebben a kategóriában</span>';
|
||||||
|
?>
|
||||||
|
<div style="font-size:11px;color:#888;margin-top:4px;">
|
||||||
|
A szolgáltatás kategóriából származtatva - a kategória módosításával változik.
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="formRow">
|
|
||||||
<label class="formTitle">Barber</label>
|
|
||||||
<select class="formDropdownBox" style="padding:0;" name="is_barber">
|
|
||||||
<option value="1" <?php echo $selectedItem->is_barber?'selected':'';?>>igen</option>
|
|
||||||
<option value="0" <?php echo !$selectedItem->is_barber?'selected':'';?>>nem</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="formRow">
|
<div class="formRow">
|
||||||
|
|||||||
@@ -11,8 +11,7 @@
|
|||||||
<td>Profilkép</td>
|
<td>Profilkép</td>
|
||||||
<td>Név</td>
|
<td>Név</td>
|
||||||
<td>Leírás</td>
|
<td>Leírás</td>
|
||||||
<td>Beauty</td>
|
<td>Vertikálok</td>
|
||||||
<td>Barber</td>
|
|
||||||
<td>Szerviz kategória</td>
|
<td>Szerviz kategória</td>
|
||||||
<td>Aktív</td>
|
<td>Aktív</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -30,8 +29,7 @@
|
|||||||
<td><img src="<?php echo SITEURL.'assets/img/'.$resultItem->worker_profile_img;?>" style="width:50px;margin:0;" /></td>
|
<td><img src="<?php echo SITEURL.'assets/img/'.$resultItem->worker_profile_img;?>" style="width:50px;margin:0;" /></td>
|
||||||
<td><?php echo htmlspecialchars($resultItem->worker_name, ENT_QUOTES, 'UTF-8');?></td>
|
<td><?php echo htmlspecialchars($resultItem->worker_name, ENT_QUOTES, 'UTF-8');?></td>
|
||||||
<td><?php echo htmlspecialchars($resultItem->worker_info, ENT_QUOTES, 'UTF-8');?></td>
|
<td><?php echo htmlspecialchars($resultItem->worker_info, ENT_QUOTES, 'UTF-8');?></td>
|
||||||
<td><?php echo $resultItem->is_beauty?'igen':'nem';?></td>
|
<td><?php echo $resultItem->derived_verticals !== null && $resultItem->derived_verticals !== '' ? htmlspecialchars($resultItem->derived_verticals, ENT_QUOTES, 'UTF-8') : '<span style="color:#b00;">nincs szolgáltatás</span>';?></td>
|
||||||
<td><?php echo $resultItem->is_barber?'igen':'nem';?></td>
|
|
||||||
<td><?php echo htmlspecialchars($resultItem->serv_cat_name, ENT_QUOTES, 'UTF-8');?></td>
|
<td><?php echo htmlspecialchars($resultItem->serv_cat_name, ENT_QUOTES, 'UTF-8');?></td>
|
||||||
<td><?php echo $resultItem->is_active?'igen':'nem';?></td>
|
<td><?php echo $resultItem->is_active?'igen':'nem';?></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Generic site footer for any vertical.
|
||||||
|
*
|
||||||
|
* Expects $vertical and $selectedLang.
|
||||||
|
*
|
||||||
|
* Replaces four near-identical <footer> copies per vertical file. The address,
|
||||||
|
* org number and map link are salon-wide; only the social accounts and the map
|
||||||
|
* image are per-vertical, and both come from the registry.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$labels = array(
|
||||||
|
'en' => array(
|
||||||
|
'orgnr' => 'Organisation number',
|
||||||
|
'vacancies' => 'Open positions',
|
||||||
|
'copyright' => '© Studio Beve - All rights reserved.',
|
||||||
|
),
|
||||||
|
'no' => array(
|
||||||
|
'orgnr' => 'Organisasjonsnummer',
|
||||||
|
'vacancies' => 'Ledige stillinger',
|
||||||
|
'copyright' => '© Studio Beve - All rights reserved.',
|
||||||
|
),
|
||||||
|
'hu' => array(
|
||||||
|
'orgnr' => 'Cégjegyzékszám',
|
||||||
|
'vacancies' => 'Állásajánlatok',
|
||||||
|
'copyright' => '© Studio Beve - All rights reserved.',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$lang = vertical_lang(isset($selectedLang) ? $selectedLang : 'en');
|
||||||
|
$t = $labels[$lang];
|
||||||
|
|
||||||
|
$mapUrl = 'https://www.google.com/maps/place/Studio+Beve/@63.4370671,10.4348909,19z/data=!3m1!4b1!4m6!3m5!1s0x466d31f2b1166d2b:0x76228adf28216c74!8m2!3d63.4370671!4d10.4355346!16s%2Fg%2F11vlvkh6w4?entry=ttu';
|
||||||
|
?>
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer id="footer">
|
||||||
|
<div class="container footer-div">
|
||||||
|
<div class="footer-bal">
|
||||||
|
<div class="contact-block">
|
||||||
|
<ul>
|
||||||
|
<li class="companyname"><span>Studio Beve AS</span></li>
|
||||||
|
<li><span>Innherredsveien 92.<br> 7043 Trondheim, Norway</span></li>
|
||||||
|
<li><span><?php echo $t['orgnr'];?>: 932 941 619</span></li>
|
||||||
|
<li><span><a href="mailto:info@studiobeve.no">info@studiobeve.no</a></span></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<ul class="icons">
|
||||||
|
<li><a href="<?php echo $vertical['facebook'];?>" class="icon brands fa-facebook-f"><span class="label">Facebook</span></a></li>
|
||||||
|
<li><a href="<?php echo $vertical['instagram'];?>" class="icon brands fa-instagram"><span class="label">Instagram</span></a></li>
|
||||||
|
</ul>
|
||||||
|
<a href="<?php echo SITEURL;?>ledigestilling/" class="footer-vacancies"><?php echo $t['vacancies'];?></a>
|
||||||
|
</div>
|
||||||
|
<div class="footer-jobb">
|
||||||
|
<a href="<?php echo $mapUrl;?>" target="_blank"><img src="<?php echo SITEURL.$vertical['map_img'];?>"> </a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="copyright">
|
||||||
|
<?php echo $t['copyright'];?>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Generic <head> for any vertical.
|
||||||
|
*
|
||||||
|
* Expects $vertical (a row from application/config/verticals.php).
|
||||||
|
* Replaces the per-vertical barber-head.php / beauty-head.php, which differ
|
||||||
|
* only in <title>, og:site_name, og:url, meta description and the stylesheet.
|
||||||
|
*/
|
||||||
|
$this->load->helper('url');
|
||||||
|
?>
|
||||||
|
<head>
|
||||||
|
<!-- Google Tag Manager -->
|
||||||
|
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
||||||
|
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
||||||
|
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
||||||
|
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
||||||
|
})(window,document,'script','dataLayer','GTM-TWRHH7DN');</script>
|
||||||
|
<!-- End Google Tag Manager -->
|
||||||
|
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
|
||||||
|
<title><?php echo htmlspecialchars($vertical['title'], ENT_QUOTES, 'UTF-8');?></title>
|
||||||
|
<meta property="fb:app_id" content="285150047390571" />
|
||||||
|
<meta property="og:site_name" content="<?php echo htmlspecialchars($vertical['og_site_name'], ENT_QUOTES, 'UTF-8');?>">
|
||||||
|
<meta property="og:image" content="<?php echo SITEURL;?>assets/img/studiobeve_facebook.jpg"/>
|
||||||
|
<meta property="og:title" content="Studio Beve" />
|
||||||
|
<meta property="og:description" content="<?php echo htmlspecialchars($vertical['og_description'], ENT_QUOTES, 'UTF-8');?>" />
|
||||||
|
<meta property="og:url" content="<?php echo SITEURL.$vertical['slug'];?>" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta name="description" content="<?php echo htmlspecialchars($vertical['meta_description'], ENT_QUOTES, 'UTF-8');?>">
|
||||||
|
<link rel="icon" type="image/x-icon" href="<?php echo base_url();?>assets/img/favicon/favicon.ico" />
|
||||||
|
<link rel="icon" type="image/png" href="<?php echo base_url();?>assets/img/favicon/favicon.png" />
|
||||||
|
<link rel="icon" type="image/gif" href="<?php echo base_url();?>assets/img/favicon/favicon.gif" />
|
||||||
|
<!-- Opera Speed Dial Favicon -->
|
||||||
|
<link rel="icon" type="image/png" href="<?php echo base_url();?>assets/img/favicon/speeddial-160px.png" />
|
||||||
|
<!-- For iPhone 4 Retina display: -->
|
||||||
|
<script src="<?php echo base_url();?>assets/js/jquery/jquery.js"></script>
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="<?php echo base_url();?>assets/img/favicon/apple-touch-icon-114x114-precomposed.png">
|
||||||
|
<link rel="stylesheet" href="<?php echo base_url();?>assets/css/<?php echo $vertical['css'];?>" />
|
||||||
|
<noscript><link rel="stylesheet" href="<?php echo base_url();?>assets/css/noscript.css" /></noscript>
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Abril+Fatface&family=Open+Sans:ital,wght@0,700;0,800;1,700;1,800&display=swap" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="<?php echo base_url();?>assets/js/jquery/jquery-ui.css">
|
||||||
|
<script src="<?php echo base_url();?>assets/js/jquery/jquery-ui.js"></script>
|
||||||
|
<script src="https://momentjs.com/downloads/moment-with-locales.js"></script>
|
||||||
|
<!-- Start cookieyes banner --> <script id="cookieyes" type="text/javascript" src="https://cdn-cookieyes.com/client_data/82ccb0b38ad63612e4c6a3fa/script.js"></script> <!-- End cookieyes banner -->
|
||||||
|
<link rel="stylesheet" type="text/css" href="<?php echo base_url();?>assets/css/style.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="<?php echo base_url();?>assets/css/responsive.css">
|
||||||
|
<script src="<?php echo base_url();?>assets/js/script.js"></script>
|
||||||
|
</head>
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Generic site header for any vertical.
|
||||||
|
*
|
||||||
|
* Expects $vertical and $selectedLang.
|
||||||
|
*
|
||||||
|
* The per-vertical headers this replaces carried FOUR near-identical copies of
|
||||||
|
* the same <ul> - one per language plus an unlabelled else-fallback that was
|
||||||
|
* reached whenever $selectedLang was not en/hu/no (and which referenced
|
||||||
|
* $currentPageUrlArray before it was defined). Here there is one nav and one
|
||||||
|
* label table, so the fallback cannot drift from the real branches.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$labels = array(
|
||||||
|
'en' => array(
|
||||||
|
'home' => 'Home', 'about' => 'About US', 'treatments' => 'Treatments',
|
||||||
|
'prices' => 'Prices', 'hours' => 'Opening Hours', 'contact' => 'Contact',
|
||||||
|
'book' => 'BOOK TIME',
|
||||||
|
),
|
||||||
|
'no' => array(
|
||||||
|
'home' => 'Forside', 'about' => 'Om oss', 'treatments' => 'Behandlinger',
|
||||||
|
'prices' => 'Priser', 'hours' => 'Åpningstider', 'contact' => 'Kontakt',
|
||||||
|
'book' => 'BESTILL TIME',
|
||||||
|
),
|
||||||
|
'hu' => array(
|
||||||
|
'home' => 'Kezdőlap', 'about' => 'Rólunk', 'treatments' => 'Szolgáltatások',
|
||||||
|
'prices' => 'Árlista', 'hours' => 'Nyitvatartás', 'contact' => 'Kapcsolat',
|
||||||
|
'book' => 'IDŐPONTFOGLALÁS',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$lang = vertical_lang(isset($selectedLang) ? $selectedLang : 'en');
|
||||||
|
$t = $labels[$lang];
|
||||||
|
|
||||||
|
// Language switcher: rebuild the current URL with a different language segment.
|
||||||
|
// Segment 1 is the language, 2 and 3 are the page path.
|
||||||
|
$currentPageUrlArray = explode('/', $_SERVER['REQUEST_URI']);
|
||||||
|
$currentPageUrlArray += array(1 => '', 2 => '', 3 => '');
|
||||||
|
?>
|
||||||
|
<!-- Header -->
|
||||||
|
<header id="header">
|
||||||
|
<a href="<?php echo SITEURL;?>"><img src="<?php echo SITEURL;?>assets/img/<?php echo $vertical['logo'];?>" class="logo-kep"></a> <h1><?php echo htmlspecialchars($vertical['heading'], ENT_QUOTES, 'UTF-8');?></h1>
|
||||||
|
<nav id="nav">
|
||||||
|
<ul>
|
||||||
|
<li><a href="<?php echo SITEURL;?>"><?php echo $t['home'];?></a></li>
|
||||||
|
<li><a href="#aboutus"><?php echo $t['about'];?></a></li>
|
||||||
|
<li><a href="#treatments"><?php echo $t['treatments'];?></a></li>
|
||||||
|
<li><a href="#one"><?php echo $t['prices'];?></a></li>
|
||||||
|
<li><a href="#two"><?php echo $t['hours'];?></a></li>
|
||||||
|
<li><a href="#footer"><?php echo $t['contact'];?></a></li>
|
||||||
|
<li class="booktime"><a href="<?php echo SITEURL.$lang.'/booking/'.$vertical['slug'];?>"><?php echo $t['book'];?></a></li>
|
||||||
|
<li class="socialmedia-menu"><a href="<?php echo $vertical['facebook'];?>" class="icon brands fa-facebook-f"><span class="label">Facebook</span></a></li>
|
||||||
|
<li class="socialmedia-menu"><a href="<?php echo $vertical['instagram'];?>" class="icon brands fa-instagram"><span class="label">Instagram</span></a></li>
|
||||||
|
<?php foreach(array('no', 'en', 'hu') as $switchLang): ?>
|
||||||
|
<li class="language"><a href="<?php echo SITEURL.$switchLang.'/'.$currentPageUrlArray[2].'/'.$currentPageUrlArray[3];?>"><?php echo strtoupper($switchLang);?></a></li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
<?php
|
||||||
|
include(getcwd().'/application/views/includes/vertical-footer.php');
|
||||||
|
?>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="<?php echo SITEURL;?>assets/js/jquery.dropotron.min.js"></script>
|
||||||
|
<script src="<?php echo SITEURL;?>assets/js/browser.min.js"></script>
|
||||||
|
<script src="<?php echo SITEURL;?>assets/js/breakpoints.min.js"></script>
|
||||||
|
<script src="<?php echo SITEURL;?>assets/js/util.js"></script>
|
||||||
|
<script src="<?php echo SITEURL;?>assets/js/studiobave.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<?php
|
||||||
|
include(getcwd().'/application/views/includes/vertical-head.php');
|
||||||
|
?>
|
||||||
|
<body class="is-preload">
|
||||||
|
<!-- Google Tag Manager (noscript) -->
|
||||||
|
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-TWRHH7DN"
|
||||||
|
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
|
||||||
|
<!-- End Google Tag Manager -->
|
||||||
|
|
||||||
|
<!-- Wrapper -->
|
||||||
|
<div id="wrapper">
|
||||||
|
<!-- Header -->
|
||||||
|
<!-- Menu -->
|
||||||
|
<!-- Main -->
|
||||||
|
<div id="main">
|
||||||
|
<?php
|
||||||
|
include(getcwd().'/application/views/includes/vertical-header.php');
|
||||||
|
?>
|
||||||
|
<div class="inner">
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
<p>
|
<p>
|
||||||
I believe that beauty, fashion, and trend are not gender-specific, so we have the
|
I believe that beauty, fashion, and trend are not gender-specific, so we have the
|
||||||
opportunity for everyone to become beautiful in one place, regardless of gender.
|
opportunity for everyone to become beautiful in one place, regardless of gender.
|
||||||
And among our Barber and Beauty departments, you can find the right services
|
And among our Barber, Beauty and Massage departments, you can find the right services
|
||||||
for you.
|
for you.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
A minőségi idő, a maximális figyelem, a legprofesszionálisabb eszközök, a hivatástudattal és szakértelemmel karöltve jelentik a filozófiánk és szolgáltatásaink alapjait.
|
A minőségi idő, a maximális figyelem, a legprofesszionálisabb eszközök, a hivatástudattal és szakértelemmel karöltve jelentik a filozófiánk és szolgáltatásaink alapjait.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Hiszem, hogy a szépség, a divat és a trend nem nemhez kötött, így nálunk lehetőség van arra, hogy mindenki egy helyen szépülhessen nemtől függetlenül. A Barber és Beauty részlegeink között pedig megtalálhatjátok a számotokra megfelelő szolgáltatásokat.
|
Hiszem, hogy a szépség, a divat és a trend nem nemhez kötött, így nálunk lehetőség van arra, hogy mindenki egy helyen szépülhessen nemtől függetlenül. A Barber, Beauty és Masszázs részlegeink között pedig megtalálhatjátok a számotokra megfelelő szolgáltatásokat.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Közel 10 éves szépségipari, és közte több éves nemzetközi tapasztalattal elérkezettnek láttam az időt, hogy megnyissam saját stúdiómat itt Trondheimben, az Innheredsveien 92 szám alatt, ahol a vendégeknek lehetősége van ingyenes parkolásra is a kezelések időtartama alatt.
|
Közel 10 éves szépségipari, és közte több éves nemzetközi tapasztalattal elérkezettnek láttam az időt, hogy megnyissam saját stúdiómat itt Trondheimben, az Innheredsveien 92 szám alatt, ahol a vendégeknek lehetősége van ingyenes parkolásra is a kezelések időtartama alatt.
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
Kvalitetstid, maksimal oppmerksomhet, de mest profesjonelle verktøyene, hånd i hånd med profesjonalitet og kompetanse, utgjør grunnlaget for vår filosofi og våre tjenester.
|
Kvalitetstid, maksimal oppmerksomhet, de mest profesjonelle verktøyene, hånd i hånd med profesjonalitet og kompetanse, utgjør grunnlaget for vår filosofi og våre tjenester.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Jeg mener at skjønnhet, mote og trend ikke er kjønnsspesifikke, og hos oss har derfor alle mulighet til å bli vakrere på ett sted, uavhengig av kjønn. Hos Studio Beve Barber og Studio Beve Beauty kan dere finne de tjenestene som er riktige for dere.
|
Jeg mener at skjønnhet, mote og trend ikke er kjønnsspesifikke, og hos oss har derfor alle mulighet til å bli vakrere på ett sted, uavhengig av kjønn. Hos Studio Beve Barber, Studio Beve Beauty og Studio Beve Massasje kan dere finne de tjenestene som er riktige for dere.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Med nesten 10 års erfaring fra skjønnhetsindustrien, inkludert mange års internasjonal erfaring, tenkte jeg det var på tide å åpne mitt eget studio her i Trondheim i Innheredsveien 92, hvor gjestene har mulighet til å parkere gratis under behandlingene.
|
Med nesten 10 års erfaring fra skjønnhetsindustrien, inkludert mange års internasjonal erfaring, tenkte jeg det var på tide å åpne mitt eget studio her i Trondheim i Innheredsveien 92, hvor gjestene har mulighet til å parkere gratis under behandlingene.
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
<p>
|
<p>
|
||||||
I believe that beauty, fashion, and trend are not gender-specific, so we have the
|
I believe that beauty, fashion, and trend are not gender-specific, so we have the
|
||||||
opportunity for everyone to become beautiful in one place, regardless of gender.
|
opportunity for everyone to become beautiful in one place, regardless of gender.
|
||||||
And among our Barber and Beauty departments, you can find the right services
|
And among our Barber, Beauty and Massage departments, you can find the right services
|
||||||
for you.
|
for you.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
<p>
|
<p>
|
||||||
Hiszem, hogy a szépség, a divat és a trend nem nemhez kötött, így nálunk
|
Hiszem, hogy a szépség, a divat és a trend nem nemhez kötött, így nálunk
|
||||||
lehetőség van arra, hogy mindenki egy helyen szépülhessen nemtől függetlenül.
|
lehetőség van arra, hogy mindenki egy helyen szépülhessen nemtől függetlenül.
|
||||||
A Barber és Beauty részlegeink között pedig megtalálhatjátok a számotokra
|
A Barber, Beauty és Masszázs részlegeink között pedig megtalálhatjátok a számotokra
|
||||||
megfelelő szolgáltatásokat.
|
megfelelő szolgáltatásokat.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
<p>
|
<p>
|
||||||
Jeg mener at skjønnhet, mote og trend ikke er kjønnsspesifikke, og hos oss har
|
Jeg mener at skjønnhet, mote og trend ikke er kjønnsspesifikke, og hos oss har
|
||||||
derfor alle mulighet til å bli vakrere på ett sted, uavhengig av kjønn. Hos Studio
|
derfor alle mulighet til å bli vakrere på ett sted, uavhengig av kjønn. Hos Studio
|
||||||
Beve Barber og Studio Beve Beauty kan dere finne de tjenestene som er riktige
|
Beve Barber, Studio Beve Beauty og Studio Beve Massasje kan dere finne de tjenestene som er riktige
|
||||||
for dere.
|
for dere.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
'alternate_week' => 'The selected staff member only works every second week. Please choose another day.',
|
'alternate_week' => 'The selected staff member only works every second week. Please choose another day.',
|
||||||
'after_hours' => 'The treatment would not finish before closing time. Please choose an earlier time.',
|
'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.',
|
'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.',
|
||||||
|
'single_service_only' => 'Only one treatment can be booked at a time. Please select just one.',
|
||||||
|
'no_service' => 'No service was selected. Please choose at least one service.',
|
||||||
'default' => 'Something went wrong with your booking. Please try again.',
|
'default' => 'Something went wrong with your booking. Please try again.',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
'alternate_week' => 'A kiválasztott kolléga csak kéthetente dolgozik. Kérjük, válasszon másik napot.',
|
'alternate_week' => 'A kiválasztott kolléga csak kéthetente dolgozik. Kérjük, válasszon másik napot.',
|
||||||
'after_hours' => 'A kezelés nem érne véget zárásig. Kérjük, válasszon korábbi időpontot.',
|
'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.',
|
'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.',
|
||||||
|
'single_service_only' => 'Egyszerre csak egy kezelés foglalható. Kérjük, csak egyet válasszon.',
|
||||||
|
'no_service' => 'Nem választott ki szolgáltatást. Kérjük, válasszon legalább egyet.',
|
||||||
'default' => 'Hiba történt a foglalás során. Kérjük, próbálja újra.',
|
'default' => 'Hiba történt a foglalás során. Kérjük, próbálja újra.',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
'alternate_week' => 'Den valgte medarbeideren jobber kun annenhver uke. Vennligst velg en annen dag.',
|
'alternate_week' => 'Den valgte medarbeideren jobber kun annenhver uke. Vennligst velg en annen dag.',
|
||||||
'after_hours' => 'Behandlingen rekker ikke å bli ferdig innen stengetid. Vennligst velg et tidligere tidspunkt.',
|
'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.',
|
'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.',
|
||||||
|
'single_service_only' => 'Du kan kun bestille én behandling om gangen. Vennligst velg kun én.',
|
||||||
|
'no_service' => 'Du har ikke valgt noen tjeneste. Vennligst velg minst én tjeneste.',
|
||||||
'default' => 'Noe gikk galt med bestillingen. Vennligst prøv igjen.',
|
'default' => 'Noe gikk galt med bestillingen. Vennligst prøv igjen.',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -95,8 +95,8 @@
|
|||||||
foreach ($groups[$label] as $serviceItem) {
|
foreach ($groups[$label] as $serviceItem) {
|
||||||
?>
|
?>
|
||||||
<div class="serviceRow">
|
<div class="serviceRow">
|
||||||
<div class="serviceCol serviceNameCol" id="serviceName_<?php echo $serviceItem->service_id; ?>">
|
<div class="serviceCol serviceNameCol" id="serviceName_<?php echo $serviceItem->service_id; ?>" data-service-name="<?php echo htmlspecialchars($serviceItem->service_name, ENT_QUOTES, 'UTF-8'); ?>">
|
||||||
<?php echo $serviceItem->service_name; ?>
|
<?php echo vertical_service_label(isset($vertical) ? $vertical : NULL, $serviceItem); ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="serviceCol">
|
<div class="serviceCol">
|
||||||
@@ -236,6 +236,26 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
<?php if ( ! empty($vertical['single_service_booking'])): ?>
|
||||||
|
/* Single-service verticals (massage): a guest books one treatment at a
|
||||||
|
time, so selecting one clears and disables the rest. Clicking the
|
||||||
|
selected one again releases everything - the escape hatch for a
|
||||||
|
mis-click. Bound BEFORE the totals handler below, so that handler
|
||||||
|
always sees the corrected state. */
|
||||||
|
$('.service').click(function(){
|
||||||
|
if($(this).is(':checked')){
|
||||||
|
$('.service').not(this)
|
||||||
|
.prop('checked', false)
|
||||||
|
.prop('disabled', true)
|
||||||
|
.closest('.serviceRow').addClass('serviceRowDisabled');
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$('.service').prop('disabled', false);
|
||||||
|
$('.serviceRow').removeClass('serviceRowDisabled');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
$('.service').click(function(){
|
$('.service').click(function(){
|
||||||
var totalPrice = 0;
|
var totalPrice = 0;
|
||||||
var selectedServices = '<div class="selectedServiceTable">';
|
var selectedServices = '<div class="selectedServiceTable">';
|
||||||
@@ -249,7 +269,10 @@
|
|||||||
var selected_id = $(this).attr('id');
|
var selected_id = $(this).attr('id');
|
||||||
selectedPriceElement = document.getElementById('servicePrice_'+selected_id).innerHTML;
|
selectedPriceElement = document.getElementById('servicePrice_'+selected_id).innerHTML;
|
||||||
totalPrice = totalPrice + parseInt(selectedPriceElement);
|
totalPrice = totalPrice + parseInt(selectedPriceElement);
|
||||||
selectedNameElement = document.getElementById('serviceName_'+selected_id).innerHTML;
|
var nameNode = document.getElementById('serviceName_'+selected_id);
|
||||||
|
// Prefer the full name: the visible label may have had its
|
||||||
|
// category prefix stripped for readability.
|
||||||
|
selectedNameElement = nameNode.getAttribute('data-service-name') || nameNode.innerHTML;
|
||||||
selectedServices = selectedServices + '<div class="totalServiceRow"><div class="selectedServiceCol totalSelectedServiceName">'+selectedNameElement+'</div><div class="selectedServiceCol totalSelectedServicePrice">'+selectedPriceElement+' kr</div></div>';
|
selectedServices = selectedServices + '<div class="totalServiceRow"><div class="selectedServiceCol totalSelectedServiceName">'+selectedNameElement+'</div><div class="selectedServiceCol totalSelectedServicePrice">'+selectedPriceElement+' kr</div></div>';
|
||||||
|
|
||||||
var selectedTotalTime = $('#servicelength').val();
|
var selectedTotalTime = $('#servicelength').val();
|
||||||
@@ -355,8 +378,13 @@
|
|||||||
},
|
},
|
||||||
}).done(function(result){
|
}).done(function(result){
|
||||||
$('#workerTable').html(result.workerListShow);
|
$('#workerTable').html(result.workerListShow);
|
||||||
var firstWorker = result.workers;
|
if(result.workers && result.workers.length > 0){
|
||||||
setWorker(firstWorker[0].worker_id)
|
setWorker(result.workers[0].worker_id);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$('#workerTable').html('<div class="noWorkerMessage">No staff available for this service.</div>');
|
||||||
|
setWorker('');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -95,8 +95,8 @@
|
|||||||
foreach ($groups[$label] as $serviceItem) {
|
foreach ($groups[$label] as $serviceItem) {
|
||||||
?>
|
?>
|
||||||
<div class="serviceRow">
|
<div class="serviceRow">
|
||||||
<div class="serviceCol serviceNameCol" id="serviceName_<?php echo $serviceItem->service_id; ?>">
|
<div class="serviceCol serviceNameCol" id="serviceName_<?php echo $serviceItem->service_id; ?>" data-service-name="<?php echo htmlspecialchars($serviceItem->service_name, ENT_QUOTES, 'UTF-8'); ?>">
|
||||||
<?php echo $serviceItem->service_name; ?>
|
<?php echo vertical_service_label(isset($vertical) ? $vertical : NULL, $serviceItem); ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="serviceCol">
|
<div class="serviceCol">
|
||||||
@@ -235,6 +235,26 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
<?php if ( ! empty($vertical['single_service_booking'])): ?>
|
||||||
|
/* Single-service verticals (massage): a guest books one treatment at a
|
||||||
|
time, so selecting one clears and disables the rest. Clicking the
|
||||||
|
selected one again releases everything - the escape hatch for a
|
||||||
|
mis-click. Bound BEFORE the totals handler below, so that handler
|
||||||
|
always sees the corrected state. */
|
||||||
|
$('.service').click(function(){
|
||||||
|
if($(this).is(':checked')){
|
||||||
|
$('.service').not(this)
|
||||||
|
.prop('checked', false)
|
||||||
|
.prop('disabled', true)
|
||||||
|
.closest('.serviceRow').addClass('serviceRowDisabled');
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$('.service').prop('disabled', false);
|
||||||
|
$('.serviceRow').removeClass('serviceRowDisabled');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
$('.service').click(function(){
|
$('.service').click(function(){
|
||||||
var totalPrice = 0;
|
var totalPrice = 0;
|
||||||
var selectedServices = '<div class="selectedServiceTable">';
|
var selectedServices = '<div class="selectedServiceTable">';
|
||||||
@@ -248,7 +268,10 @@
|
|||||||
var selected_id = $(this).attr('id');
|
var selected_id = $(this).attr('id');
|
||||||
selectedPriceElement = document.getElementById('servicePrice_'+selected_id).innerHTML;
|
selectedPriceElement = document.getElementById('servicePrice_'+selected_id).innerHTML;
|
||||||
totalPrice = totalPrice + parseInt(selectedPriceElement);
|
totalPrice = totalPrice + parseInt(selectedPriceElement);
|
||||||
selectedNameElement = document.getElementById('serviceName_'+selected_id).innerHTML;
|
var nameNode = document.getElementById('serviceName_'+selected_id);
|
||||||
|
// Prefer the full name: the visible label may have had its
|
||||||
|
// category prefix stripped for readability.
|
||||||
|
selectedNameElement = nameNode.getAttribute('data-service-name') || nameNode.innerHTML;
|
||||||
selectedServices = selectedServices + '<div class="totalServiceRow"><div class="selectedServiceCol totalSelectedServiceName">'+selectedNameElement+'</div><div class="selectedServiceCol totalSelectedServicePrice">'+selectedPriceElement+' kr</div></div>';
|
selectedServices = selectedServices + '<div class="totalServiceRow"><div class="selectedServiceCol totalSelectedServiceName">'+selectedNameElement+'</div><div class="selectedServiceCol totalSelectedServicePrice">'+selectedPriceElement+' kr</div></div>';
|
||||||
|
|
||||||
var selectedTotalTime = $('#servicelength').val();
|
var selectedTotalTime = $('#servicelength').val();
|
||||||
@@ -356,8 +379,13 @@
|
|||||||
},
|
},
|
||||||
}).done(function(result){
|
}).done(function(result){
|
||||||
$('#workerTable').html(result.workerListShow);
|
$('#workerTable').html(result.workerListShow);
|
||||||
var firstWorker = result.workers;
|
if(result.workers && result.workers.length > 0){
|
||||||
setWorker(firstWorker[0].worker_id)
|
setWorker(result.workers[0].worker_id);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$('#workerTable').html('<div class="noWorkerMessage">Nincs elérhető munkatárs ehhez a szolgáltatáshoz.</div>');
|
||||||
|
setWorker('');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -95,8 +95,8 @@ if (is_array($services) && count($services) > 0) {
|
|||||||
foreach ($groups[$label] as $serviceItem) {
|
foreach ($groups[$label] as $serviceItem) {
|
||||||
?>
|
?>
|
||||||
<div class="serviceRow">
|
<div class="serviceRow">
|
||||||
<div class="serviceCol serviceNameCol" id="serviceName_<?php echo $serviceItem->service_id; ?>">
|
<div class="serviceCol serviceNameCol" id="serviceName_<?php echo $serviceItem->service_id; ?>" data-service-name="<?php echo htmlspecialchars($serviceItem->service_name, ENT_QUOTES, 'UTF-8'); ?>">
|
||||||
<?php echo $serviceItem->service_name; ?>
|
<?php echo vertical_service_label(isset($vertical) ? $vertical : NULL, $serviceItem); ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="serviceCol">
|
<div class="serviceCol">
|
||||||
@@ -235,6 +235,26 @@ if (is_array($services) && count($services) > 0) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
<?php if ( ! empty($vertical['single_service_booking'])): ?>
|
||||||
|
/* Single-service verticals (massage): a guest books one treatment at a
|
||||||
|
time, so selecting one clears and disables the rest. Clicking the
|
||||||
|
selected one again releases everything - the escape hatch for a
|
||||||
|
mis-click. Bound BEFORE the totals handler below, so that handler
|
||||||
|
always sees the corrected state. */
|
||||||
|
$('.service').click(function(){
|
||||||
|
if($(this).is(':checked')){
|
||||||
|
$('.service').not(this)
|
||||||
|
.prop('checked', false)
|
||||||
|
.prop('disabled', true)
|
||||||
|
.closest('.serviceRow').addClass('serviceRowDisabled');
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$('.service').prop('disabled', false);
|
||||||
|
$('.serviceRow').removeClass('serviceRowDisabled');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
$('.service').click(function(){
|
$('.service').click(function(){
|
||||||
var totalPrice = 0;
|
var totalPrice = 0;
|
||||||
var selectedServices = '<div class="selectedServiceTable">';
|
var selectedServices = '<div class="selectedServiceTable">';
|
||||||
@@ -248,7 +268,10 @@ if (is_array($services) && count($services) > 0) {
|
|||||||
var selected_id = $(this).attr('id');
|
var selected_id = $(this).attr('id');
|
||||||
selectedPriceElement = document.getElementById('servicePrice_'+selected_id).innerHTML;
|
selectedPriceElement = document.getElementById('servicePrice_'+selected_id).innerHTML;
|
||||||
totalPrice = totalPrice + parseInt(selectedPriceElement);
|
totalPrice = totalPrice + parseInt(selectedPriceElement);
|
||||||
selectedNameElement = document.getElementById('serviceName_'+selected_id).innerHTML;
|
var nameNode = document.getElementById('serviceName_'+selected_id);
|
||||||
|
// Prefer the full name: the visible label may have had its
|
||||||
|
// category prefix stripped for readability.
|
||||||
|
selectedNameElement = nameNode.getAttribute('data-service-name') || nameNode.innerHTML;
|
||||||
selectedServices = selectedServices + '<div class="totalServiceRow"><div class="selectedServiceCol totalSelectedServiceName">'+selectedNameElement+'</div><div class="selectedServiceCol totalSelectedServicePrice">'+selectedPriceElement+' kr</div></div>';
|
selectedServices = selectedServices + '<div class="totalServiceRow"><div class="selectedServiceCol totalSelectedServiceName">'+selectedNameElement+'</div><div class="selectedServiceCol totalSelectedServicePrice">'+selectedPriceElement+' kr</div></div>';
|
||||||
|
|
||||||
var selectedTotalTime = $('#servicelength').val();
|
var selectedTotalTime = $('#servicelength').val();
|
||||||
@@ -354,8 +377,13 @@ if (is_array($services) && count($services) > 0) {
|
|||||||
},
|
},
|
||||||
}).done(function(result){
|
}).done(function(result){
|
||||||
$('#workerTable').html(result.workerListShow);
|
$('#workerTable').html(result.workerListShow);
|
||||||
var firstWorker = result.workers;
|
if(result.workers && result.workers.length > 0){
|
||||||
setWorker(firstWorker[0].worker_id)
|
setWorker(result.workers[0].worker_id);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$('#workerTable').html('<div class="noWorkerMessage">Ingen ledige medarbeidere for denne tjenesten.</div>');
|
||||||
|
setWorker('');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +1,25 @@
|
|||||||
<section class="tiles">
|
<section class="tiles">
|
||||||
<article class="style2">
|
<?php
|
||||||
|
/**
|
||||||
|
* Home tiles are driven by the vertical registry: every enabled vertical
|
||||||
|
* flagged 'public' gets a tile, ordered by 'sort'. Adding a fourth vertical
|
||||||
|
* is a config entry, not an edit here.
|
||||||
|
*
|
||||||
|
* The <img> is only a size spacer - the visible artwork is the CSS
|
||||||
|
* .tiles article.styleN > .image:before background, keyed off tile_class.
|
||||||
|
*
|
||||||
|
* The 'no/' language prefix matches the previous hardcoded links; the home
|
||||||
|
* page has no language variant of its own.
|
||||||
|
*/
|
||||||
|
foreach(vertical_public() as $verticalItem):
|
||||||
|
?>
|
||||||
|
<article class="<?php echo $verticalItem['tile_class'];?>">
|
||||||
<span class="image">
|
<span class="image">
|
||||||
<img src="<?php echo SITEURL;?>assets/img/pic03.jpg" alt="" />
|
<img src="<?php echo SITEURL.$verticalItem['tile_spacer'];?>" alt="" />
|
||||||
</span>
|
</span>
|
||||||
<a href="<?php echo SITEURL;?>no/barber">
|
<a href="<?php echo SITEURL.'no/'.$verticalItem['slug'];?>">
|
||||||
<h2>BARBER</h2>
|
<h2><?php echo htmlspecialchars(vertical_label($verticalItem, 'en'), ENT_QUOTES, 'UTF-8');?></h2>
|
||||||
<!--div class="content">
|
|
||||||
<p>Sed nisl arcu euismod sit amet nisi lorem etiam dolor veroeros et feugiat.</p>
|
|
||||||
</div-->
|
|
||||||
</a>
|
|
||||||
</article>
|
|
||||||
<article class="style1">
|
|
||||||
<span class="image">
|
|
||||||
<img src="<?php echo SITEURL;?>assets/img/pic09.jpg" alt="" />
|
|
||||||
</span>
|
|
||||||
<a href="<?php echo SITEURL;?>no/beauty">
|
|
||||||
<h2>BEAUTY</h2>
|
|
||||||
<!--div class="content">
|
|
||||||
<p>Sed nisl arcu euismod sit amet nisi lorem etiam dolor veroeros et feugiat.</p>
|
|
||||||
</div-->
|
|
||||||
</a>
|
</a>
|
||||||
</article>
|
</article>
|
||||||
|
<?php endforeach; ?>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,293 @@
|
|||||||
|
<?php
|
||||||
|
/* -----------------------------------------------------------------------
|
||||||
|
* Massage vertical landing content - English.
|
||||||
|
*
|
||||||
|
* Bio, treatment names and descriptions supplied by the salon.
|
||||||
|
* Generated from one template so massage-form-no / -en / -hu stay
|
||||||
|
* structurally identical.
|
||||||
|
*
|
||||||
|
* DURATIONS: the price list shows the treatment time from the service NAME
|
||||||
|
* (50 / 80 / 110 min). services.service_time holds the longer BOOKED slot
|
||||||
|
* (60 / 90 / 120 min) which covers changing and payment, and is never
|
||||||
|
* rendered to the guest. See prices_note below.
|
||||||
|
*
|
||||||
|
* Still a placeholder: assets/img/massage/masseur.png (therapist portrait),
|
||||||
|
* assets/img/massage/banner.jpg and map.jpg.
|
||||||
|
* -------------------------------------------------------------------- */
|
||||||
|
?>
|
||||||
|
<!-- Banner -->
|
||||||
|
<section id="banner">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/banner.jpg" style="width: 100%;" />
|
||||||
|
</section>
|
||||||
|
<section id="mobil-menu">
|
||||||
|
<div class="mobil-menucont">
|
||||||
|
<ul>
|
||||||
|
<li class="mobil-menu-book"><a href="<?php echo SITEURL;?>en/booking/massage">BOOK TIME</a></li>
|
||||||
|
<li class=""><a href="<?php echo $vertical['facebook'];?>" class="icon brands fa-facebook-f"><span class="label">Facebook</span></a></li>
|
||||||
|
<li class=""><a href="<?php echo $vertical['instagram'];?>" class="icon brands fa-instagram"><span class="label">Instagram</span></a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- About Us -->
|
||||||
|
<section id="aboutus" class="wrapper style1">
|
||||||
|
<div class="container">
|
||||||
|
<div class="inner">
|
||||||
|
<header class="major">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/ollo_rose.png">
|
||||||
|
<h2>About us</h2>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<?php /* Owner block, lifted verbatim from beauty-form-<lang>.php at
|
||||||
|
generation time so all three verticals introduce Evelin
|
||||||
|
identically. Do not edit here - edit the beauty file and
|
||||||
|
regenerate, or the two will drift. */ ?>
|
||||||
|
<div class="bemutatkozas">
|
||||||
|
<div class="bem-bal">
|
||||||
|
<p>
|
||||||
|
My name is Evelin Bence, leader and creator of Studio Beve. I consider it
|
||||||
|
important that our guests during their stay – resting a little from the noise of the
|
||||||
|
world – recharge their batteries and return to everyday life beautified inside as
|
||||||
|
well as outside.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Quality time, maximum attention, the most professional tools, together with
|
||||||
|
professionalism and expertise, stand for the basis of our philosophy and
|
||||||
|
services.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
I believe that beauty, fashion, and trend are not gender-specific, so we have the
|
||||||
|
opportunity for everyone to become beautiful in one place, regardless of gender.
|
||||||
|
And among our Barber, Beauty and Massage departments, you can find the right services
|
||||||
|
for you.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
With nearly 10 years of experience in the beauty industry, including many years
|
||||||
|
of international experience, I thought it was time to open my own studio here in
|
||||||
|
Trondheim at Innheredsveien 92, where guests can park free of charge during
|
||||||
|
the treatments.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
It is an extra pleasure for me that I managed to find a traditional place where
|
||||||
|
there was already a beauty salon in the 50s. Therefore, I now have the
|
||||||
|
opportunity to carry on this tradition in a modern environment.
|
||||||
|
Become beautiful with us. We look forward to seeing you.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="bem-jobb">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/evelin_beauty.JPG">
|
||||||
|
<h4>Evelin Bence <br> <span>Owner, Studio Beve</span></h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php /* Therapist sub-section, following the per-worker pattern
|
||||||
|
barber/beauty use: circular portrait + name, then the bio
|
||||||
|
with a photo strip alongside. */ ?>
|
||||||
|
<div class="dolgozo-nev">
|
||||||
|
<hr>
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/vincent/vincent.jpg" class="dolgozo-kep">
|
||||||
|
<h4>VINCENT Pusch <span>- Massage Therapist</span></h4>
|
||||||
|
</div>
|
||||||
|
<div class="bemutatkozas-dolgozo">
|
||||||
|
<div class="bem-dolgozo-bal">
|
||||||
|
<p>My interest in massage, manual treatment techniques, and the way the human body functions has been with me since 2011 and has, over the years, become a central part of my professional career.</p>
|
||||||
|
<p>I completed my physiotherapy education in Germany. I began my professional career at a military hospital, where I worked as a physiotherapist and manual therapist. I later continued my work at a multidisciplinary clinic before establishing and running my own private practice in Germany until I moved to Norway.</p>
|
||||||
|
<p>Over the years, I have continuously expanded my professional knowledge and experience. In addition to physiotherapy and manual therapy, I have worked with sports physiotherapy and, since 2019, also with craniosacral therapy and osteopathy. Continuous professional development and learning new methods are important to me.</p>
|
||||||
|
<p>I believe that every person and every body is different, which is why I always base my treatments on each client’s individual needs and goals. I select and combine different massage and manual techniques accordingly, whether the goal is relaxation, relieving muscle tension caused by everyday or physical strain, recovery after exercise, or simply giving the body time to recharge.</p>
|
||||||
|
<p>I have been living in Trondheim since May 2026. The process of obtaining Norwegian recognition of my foreign physiotherapy qualification is currently ongoing. At Studio Beve, I currently work as a massage therapist and offer massage and other manual treatments that do not require Norwegian authorization as healthcare personnel. Once Norwegian authorization has been obtained, my professional activities and the range of treatments I can offer may be expanded further.</p>
|
||||||
|
<p>I look forward to getting to know Studio Beve’s clients and using my professional experience to provide attentive, individually tailored treatments.</p>
|
||||||
|
</div>
|
||||||
|
<div class="bem-dolgozo-jobb">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/vincent/1.jpg">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/vincent/2.jpg">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/vincent/3.jpg">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/vincent/4.jpg">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Treatments -->
|
||||||
|
<section id="treatments" class="wrapper style2">
|
||||||
|
<div class="container">
|
||||||
|
<div class="inner">
|
||||||
|
<header class="major">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/ollo_rose.png">
|
||||||
|
<h2 class="nyitva">Treatments</h2>
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
<div class="service-block">
|
||||||
|
<div class="service-area">
|
||||||
|
<div class="one-third service-part1">
|
||||||
|
<div class="service-inner">
|
||||||
|
<div class="service service1">
|
||||||
|
<div class="service-text service-text1">
|
||||||
|
<div class="service-icon icon1"></div>
|
||||||
|
<div class="service-content">
|
||||||
|
<div class="main-title">Classic Swedish Massage</div>
|
||||||
|
<div class="sub-title-serv">full body, relaxation and well-being</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="service-text service-text2">
|
||||||
|
<div class="service-icon icon2"></div>
|
||||||
|
<div class="service-content">
|
||||||
|
<div class="main-title">Sports Massage</div>
|
||||||
|
<div class="sub-title-serv">for active individuals and athletes</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="service-text service-text3">
|
||||||
|
<div class="service-icon icon3"></div>
|
||||||
|
<div class="service-content">
|
||||||
|
<div class="main-title">Deep Tissue Massage</div>
|
||||||
|
<div class="sub-title-serv">deeper muscles and connective tissue</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="one-third service-part2">
|
||||||
|
<div class="service-inner">
|
||||||
|
<div class="service service2">
|
||||||
|
<a href="<?php echo SITEURL;?>en/booking/massage" class="banner-anchor"><img src="<?php echo base_url();?>assets/img/service-banner-massage.png" alt="massage" class="banner-image1"></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="one-third service-part3">
|
||||||
|
<div class="service-inner">
|
||||||
|
<div class="service service3">
|
||||||
|
<div class="service-text service-text1">
|
||||||
|
<div class="service-icon icon1"></div>
|
||||||
|
<div class="service-content">
|
||||||
|
<div class="main-title">Work Recovery Massage</div>
|
||||||
|
<div class="sub-title-serv">office and physical work</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="service-text service-text2">
|
||||||
|
<div class="service-icon icon2"></div>
|
||||||
|
<div class="service-content">
|
||||||
|
<div class="main-title">Studio Beve Signature</div>
|
||||||
|
<div class="sub-title-serv">individually tailored treatment</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="service-text service-text3">
|
||||||
|
<div class="service-icon icon3"></div>
|
||||||
|
<div class="service-content">
|
||||||
|
<div class="main-title">Craniosacral Treatment</div>
|
||||||
|
<div class="sub-title-serv">gentle, holistic manual treatment</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Prices -->
|
||||||
|
<section id="one" class="wrapper style1">
|
||||||
|
<div class="container">
|
||||||
|
<div class="inner">
|
||||||
|
<header class="major">
|
||||||
|
<img src="<?php echo SITEURL;?>assets/img/massage/ollo_rose.png">
|
||||||
|
<h2>Prices</h2>
|
||||||
|
<h4 class="prices-note">The stated treatment time is hands-on treatment time. The appointment reserved for you is slightly longer, allowing time to change and to pay.</h4>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Grouped by treatment type. Two deliberate differences from the
|
||||||
|
* barber/beauty price lists, both because massage sells the SAME
|
||||||
|
* treatment at two or three lengths:
|
||||||
|
*
|
||||||
|
* 1. The description is printed ONCE per group rather than once
|
||||||
|
* per duration, so a three-length treatment does not repeat
|
||||||
|
* its blurb three times.
|
||||||
|
* 2. The row label is the duration alone. services.service_name
|
||||||
|
* has to stay self-describing ("Klassisk svensk massasje -
|
||||||
|
* 50 min") because the booking form and the confirmation
|
||||||
|
* email render it with no category around it - but here the
|
||||||
|
* category heading is directly above, so repeating it just
|
||||||
|
* makes every row wrap.
|
||||||
|
*
|
||||||
|
* $services arrives ordered by service_id and the catalogue is
|
||||||
|
* inserted grouped, so a simple change-detect is enough.
|
||||||
|
*/
|
||||||
|
$prevousCategory = '';
|
||||||
|
|
||||||
|
if(is_array($services)){
|
||||||
|
foreach($services as $serviceItem){
|
||||||
|
if($serviceItem->service_category != $prevousCategory){
|
||||||
|
if($prevousCategory !== ''){
|
||||||
|
echo '<div style="clear:both;"></div>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<div class="prices-category" style="width: 100%">
|
||||||
|
<h4><?php echo $serviceItem->service_category;?></h4>
|
||||||
|
<p class="category-intro"><?php echo $serviceItem->service_description;?></p>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same rule as the booking form: the category heading is
|
||||||
|
// directly above, so the row need not repeat it.
|
||||||
|
$rowLabel = vertical_service_label($vertical, $serviceItem);
|
||||||
|
?>
|
||||||
|
<div class="one-half">
|
||||||
|
<div class="category-content">
|
||||||
|
<div class="category-text-left">
|
||||||
|
<div class="main-title"><a><?php echo $rowLabel;?></a></div>
|
||||||
|
</div>
|
||||||
|
<div class="category-text-right">
|
||||||
|
<div class="price">kr <?php echo $serviceItem->service_price;?></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
$prevousCategory = $serviceItem->service_category;
|
||||||
|
}
|
||||||
|
echo '<div style="clear:both;"></div>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Opening hours -->
|
||||||
|
<section id="two" class="wrapper style2">
|
||||||
|
<div class="container">
|
||||||
|
<div class="inner">
|
||||||
|
<header class="major">
|
||||||
|
<img src="<?php echo SITEURL;?>assets/img/massage/ollo_rose.png">
|
||||||
|
<h2 class="nyitva">Opening Hours</h2>
|
||||||
|
<h4>Free customer parking during your treatment</h4>
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
<div class="nyitvatartas">
|
||||||
|
<div class="about-content">
|
||||||
|
<div class="about-text-left">
|
||||||
|
<div class="title">Weekdays</div>
|
||||||
|
</div>
|
||||||
|
<div class="about-text-right">
|
||||||
|
<div class="time">10:00 - 18:00</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="about-content">
|
||||||
|
<div class="about-text-left">
|
||||||
|
<div class="title">Saturday</div>
|
||||||
|
</div>
|
||||||
|
<div class="about-text-right">
|
||||||
|
<div class="time">10:00 - 16:00</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="about-content">
|
||||||
|
<div class="about-text-left">
|
||||||
|
<div class="title">Sunday</div>
|
||||||
|
</div>
|
||||||
|
<div class="about-text-right">
|
||||||
|
<div class="closed">Closed</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
@@ -0,0 +1,291 @@
|
|||||||
|
<?php
|
||||||
|
/* -----------------------------------------------------------------------
|
||||||
|
* Massage vertical landing content - Hungarian.
|
||||||
|
*
|
||||||
|
* Bio, treatment names and descriptions supplied by the salon.
|
||||||
|
* Generated from one template so massage-form-no / -en / -hu stay
|
||||||
|
* structurally identical.
|
||||||
|
*
|
||||||
|
* DURATIONS: the price list shows the treatment time from the service NAME
|
||||||
|
* (50 / 80 / 110 min). services.service_time holds the longer BOOKED slot
|
||||||
|
* (60 / 90 / 120 min) which covers changing and payment, and is never
|
||||||
|
* rendered to the guest. See prices_note below.
|
||||||
|
*
|
||||||
|
* Still a placeholder: assets/img/massage/masseur.png (therapist portrait),
|
||||||
|
* assets/img/massage/banner.jpg and map.jpg.
|
||||||
|
* -------------------------------------------------------------------- */
|
||||||
|
?>
|
||||||
|
<!-- Banner -->
|
||||||
|
<section id="banner">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/banner.jpg" style="width: 100%;" />
|
||||||
|
</section>
|
||||||
|
<section id="mobil-menu">
|
||||||
|
<div class="mobil-menucont">
|
||||||
|
<ul>
|
||||||
|
<li class="mobil-menu-book"><a href="<?php echo SITEURL;?>hu/booking/massage">IDŐPONTFOGLALÁS</a></li>
|
||||||
|
<li class=""><a href="<?php echo $vertical['facebook'];?>" class="icon brands fa-facebook-f"><span class="label">Facebook</span></a></li>
|
||||||
|
<li class=""><a href="<?php echo $vertical['instagram'];?>" class="icon brands fa-instagram"><span class="label">Instagram</span></a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- About Us -->
|
||||||
|
<section id="aboutus" class="wrapper style1">
|
||||||
|
<div class="container">
|
||||||
|
<div class="inner">
|
||||||
|
<header class="major">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/ollo_rose.png">
|
||||||
|
<h2>Rólunk</h2>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<?php /* Owner block, lifted verbatim from beauty-form-<lang>.php at
|
||||||
|
generation time so all three verticals introduce Evelin
|
||||||
|
identically. Do not edit here - edit the beauty file and
|
||||||
|
regenerate, or the two will drift. */ ?>
|
||||||
|
<div class="bemutatkozas">
|
||||||
|
<div class="bem-bal">
|
||||||
|
<p>
|
||||||
|
Bence Evelin vagyok a Studio Beve vezetője és megálmodója. Fontosnak
|
||||||
|
tartom, hogy a vendégek a nálunk töltött idő alatt – egy kicsit megpihenve a világ zajától – feltöltődjenek, és kívül-belül egszépülve térjenek vissza a mindennapokhoz.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
A minőségi idő, a maximális figyelem, a legprofesszionálisabb eszközök, a
|
||||||
|
hivatástudattal és szakértelemmel karöltve jelentik a filozófiánk és
|
||||||
|
szolgáltatásaink alapjait.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Hiszem, hogy a szépség, a divat és a trend nem nemhez kötött, így nálunk
|
||||||
|
lehetőség van arra, hogy mindenki egy helyen szépülhessen nemtől függetlenül.
|
||||||
|
A Barber, Beauty és Masszázs részlegeink között pedig megtalálhatjátok a számotokra
|
||||||
|
megfelelő szolgáltatásokat.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Közel 10 éves szépségipari, és közte több éves nemzetközi tapasztalattal
|
||||||
|
elérkezettnek láttam az időt, hogy megnyissam saját stúdiómat itt
|
||||||
|
Trondheimben, az Innheredsveien 92 szám alatt, ahol a vendégeknek lehetősége
|
||||||
|
van ingyenes parkolásra is a kezelések időtartama alatt.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Extra öröm számomra, hogy egy olyan tradicionális helyet sikerült találnom,
|
||||||
|
ahol az 50-es években már szépségszalon működött, ennek köszönhetően a
|
||||||
|
hagyományt, modern környezetben lehetőségem van tovább vinni.
|
||||||
|
Szépülj velünk, szeretettel várunk.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="bem-jobb">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/evelin_beauty.JPG">
|
||||||
|
<h4>Bence Evelin <br> <span>Tulajdonos, Studio Beve</span></h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php /* Therapist sub-section, following the per-worker pattern
|
||||||
|
barber/beauty use: circular portrait + name, then the bio
|
||||||
|
with a photo strip alongside. */ ?>
|
||||||
|
<div class="dolgozo-nev">
|
||||||
|
<hr>
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/vincent/vincent.jpg" class="dolgozo-kep">
|
||||||
|
<h4>VINCENT Pusch <span>- Masszőr</span></h4>
|
||||||
|
</div>
|
||||||
|
<div class="bemutatkozas-dolgozo">
|
||||||
|
<div class="bem-dolgozo-bal">
|
||||||
|
<p>A masszázs, a manuális kezelések és az emberi test működése iránti érdeklődésem 2011 óta kísér, és az évek során szakmai pályám meghatározó részévé vált.</p>
|
||||||
|
<p>Fizioterápiás végzettségemet Németországban szereztem. Pályafutásomat katonai kórházban kezdtem, ahol fizioterapeutaként és manuálterapeutaként dolgoztam. Később multidiszciplináris rendelőben folytattam a munkámat, majd saját magánpraxist vezettem Németországban, mielőtt Norvégiába költöztem.</p>
|
||||||
|
<p>Az évek során folyamatosan bővítettem szakmai ismereteimet és tapasztalataimat. A fizioterápia és manuálterápia mellett sportfizioterápiával, valamint 2019 óta craniosacralis terápiával és oszteopátiával is foglalkozom. Fontos számomra a folyamatos szakmai fejlődés és az új módszerek megismerése.</p>
|
||||||
|
<p>Hiszek abban, hogy minden ember és minden test más, ezért a kezeléseim során mindig az egyéni igényeket és célokat tartom szem előtt. A különböző masszázs- és manuális technikákat ennek megfelelően választom ki és kombinálom, legyen szó relaxációról, a mindennapi vagy fizikai terhelés következtében kialakult izomfeszültségről, sport utáni regenerációról vagy egyszerűen a testi feltöltődésről.</p>
|
||||||
|
<p>2026 májusa óta élek Trondheimben. Külföldön megszerzett fizioterápiás képesítésem norvég elismertetése jelenleg folyamatban van. A Studio Bevében jelenleg masszőrként végzem szakmai tevékenységemet, ahol masszázs- és olyan manuális kezeléseket kínálok, amelyekhez nem szükséges norvég egészségügyi engedély. A norvég engedély megszerzésével szakmai tevékenységem és az általam kínált kezelések köre a jövőben tovább bővülhet.</p>
|
||||||
|
<p>Örömmel várom, hogy a Studio Beve vendégeit is megismerhessem, és szakmai tapasztalatommal személyre szabott, figyelmes kezelést nyújthassak számukra.</p>
|
||||||
|
</div>
|
||||||
|
<div class="bem-dolgozo-jobb">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/vincent/1.jpg">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/vincent/2.jpg">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/vincent/3.jpg">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/vincent/4.jpg">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Treatments -->
|
||||||
|
<section id="treatments" class="wrapper style2">
|
||||||
|
<div class="container">
|
||||||
|
<div class="inner">
|
||||||
|
<header class="major">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/ollo_rose.png">
|
||||||
|
<h2 class="nyitva">Szolgáltatások</h2>
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
<div class="service-block">
|
||||||
|
<div class="service-area">
|
||||||
|
<div class="one-third service-part1">
|
||||||
|
<div class="service-inner">
|
||||||
|
<div class="service service1">
|
||||||
|
<div class="service-text service-text1">
|
||||||
|
<div class="service-icon icon1"></div>
|
||||||
|
<div class="service-content">
|
||||||
|
<div class="main-title">Klasszikus svédmasszázs</div>
|
||||||
|
<div class="sub-title-serv">teljes test, lazítás és feltöltődés</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="service-text service-text2">
|
||||||
|
<div class="service-icon icon2"></div>
|
||||||
|
<div class="service-content">
|
||||||
|
<div class="main-title">Sportmasszázs</div>
|
||||||
|
<div class="sub-title-serv">aktív életmódhoz és sportolóknak</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="service-text service-text3">
|
||||||
|
<div class="service-icon icon3"></div>
|
||||||
|
<div class="service-content">
|
||||||
|
<div class="main-title">Mélyszöveti masszázs</div>
|
||||||
|
<div class="sub-title-serv">mélyebb izmok és kötőszövet</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="one-third service-part2">
|
||||||
|
<div class="service-inner">
|
||||||
|
<div class="service service2">
|
||||||
|
<a href="<?php echo SITEURL;?>hu/booking/massage" class="banner-anchor"><img src="<?php echo base_url();?>assets/img/service-banner-massage.png" alt="massage" class="banner-image1"></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="one-third service-part3">
|
||||||
|
<div class="service-inner">
|
||||||
|
<div class="service service3">
|
||||||
|
<div class="service-text service-text1">
|
||||||
|
<div class="service-icon icon1"></div>
|
||||||
|
<div class="service-content">
|
||||||
|
<div class="main-title">Irodai és fizikai munka utáni masszázs</div>
|
||||||
|
<div class="sub-title-serv">ülőmunkához és fizikai terheléshez</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="service-text service-text2">
|
||||||
|
<div class="service-icon icon2"></div>
|
||||||
|
<div class="service-content">
|
||||||
|
<div class="main-title">Studio Beve Signature</div>
|
||||||
|
<div class="sub-title-serv">személyre szabott kezelés</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="service-text service-text3">
|
||||||
|
<div class="service-icon icon3"></div>
|
||||||
|
<div class="service-content">
|
||||||
|
<div class="main-title">Craniosacralis kezelés</div>
|
||||||
|
<div class="sub-title-serv">gyengéd, holisztikus manuális kezelés</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Prices -->
|
||||||
|
<section id="one" class="wrapper style1">
|
||||||
|
<div class="container">
|
||||||
|
<div class="inner">
|
||||||
|
<header class="major">
|
||||||
|
<img src="<?php echo SITEURL;?>assets/img/massage/ollo_rose.png">
|
||||||
|
<h2>Árlista</h2>
|
||||||
|
<h4 class="prices-note">A feltüntetett kezelési idő a tényleges masszázsidőt jelenti. A lefoglalt időpont ennél valamivel hosszabb, hogy legyen idő az át­öltözésre és a fizetésre.</h4>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Grouped by treatment type. Two deliberate differences from the
|
||||||
|
* barber/beauty price lists, both because massage sells the SAME
|
||||||
|
* treatment at two or three lengths:
|
||||||
|
*
|
||||||
|
* 1. The description is printed ONCE per group rather than once
|
||||||
|
* per duration, so a three-length treatment does not repeat
|
||||||
|
* its blurb three times.
|
||||||
|
* 2. The row label is the duration alone. services.service_name
|
||||||
|
* has to stay self-describing ("Klassisk svensk massasje -
|
||||||
|
* 50 min") because the booking form and the confirmation
|
||||||
|
* email render it with no category around it - but here the
|
||||||
|
* category heading is directly above, so repeating it just
|
||||||
|
* makes every row wrap.
|
||||||
|
*
|
||||||
|
* $services arrives ordered by service_id and the catalogue is
|
||||||
|
* inserted grouped, so a simple change-detect is enough.
|
||||||
|
*/
|
||||||
|
$prevousCategory = '';
|
||||||
|
|
||||||
|
if(is_array($services)){
|
||||||
|
foreach($services as $serviceItem){
|
||||||
|
if($serviceItem->service_category != $prevousCategory){
|
||||||
|
if($prevousCategory !== ''){
|
||||||
|
echo '<div style="clear:both;"></div>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<div class="prices-category" style="width: 100%">
|
||||||
|
<h4><?php echo $serviceItem->service_category;?></h4>
|
||||||
|
<p class="category-intro"><?php echo $serviceItem->service_description;?></p>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same rule as the booking form: the category heading is
|
||||||
|
// directly above, so the row need not repeat it.
|
||||||
|
$rowLabel = vertical_service_label($vertical, $serviceItem);
|
||||||
|
?>
|
||||||
|
<div class="one-half">
|
||||||
|
<div class="category-content">
|
||||||
|
<div class="category-text-left">
|
||||||
|
<div class="main-title"><a><?php echo $rowLabel;?></a></div>
|
||||||
|
</div>
|
||||||
|
<div class="category-text-right">
|
||||||
|
<div class="price">kr <?php echo $serviceItem->service_price;?></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
$prevousCategory = $serviceItem->service_category;
|
||||||
|
}
|
||||||
|
echo '<div style="clear:both;"></div>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Opening hours -->
|
||||||
|
<section id="two" class="wrapper style2">
|
||||||
|
<div class="container">
|
||||||
|
<div class="inner">
|
||||||
|
<header class="major">
|
||||||
|
<img src="<?php echo SITEURL;?>assets/img/massage/ollo_rose.png">
|
||||||
|
<h2 class="nyitva">Nyitvatartás</h2>
|
||||||
|
<h4>Ingyenes vendégparkolás a kezelés ideje alatt</h4>
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
<div class="nyitvatartas">
|
||||||
|
<div class="about-content">
|
||||||
|
<div class="about-text-left">
|
||||||
|
<div class="title">Hétköznap</div>
|
||||||
|
</div>
|
||||||
|
<div class="about-text-right">
|
||||||
|
<div class="time">10:00 - 18:00</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="about-content">
|
||||||
|
<div class="about-text-left">
|
||||||
|
<div class="title">Szombat</div>
|
||||||
|
</div>
|
||||||
|
<div class="about-text-right">
|
||||||
|
<div class="time">10:00 - 16:00</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="about-content">
|
||||||
|
<div class="about-text-left">
|
||||||
|
<div class="title">Vasárnap</div>
|
||||||
|
</div>
|
||||||
|
<div class="about-text-right">
|
||||||
|
<div class="closed">Zárva</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
@@ -0,0 +1,293 @@
|
|||||||
|
<?php
|
||||||
|
/* -----------------------------------------------------------------------
|
||||||
|
* Massage vertical landing content - Norwegian (bokmål).
|
||||||
|
*
|
||||||
|
* Bio, treatment names and descriptions supplied by the salon.
|
||||||
|
* Generated from one template so massage-form-no / -en / -hu stay
|
||||||
|
* structurally identical.
|
||||||
|
*
|
||||||
|
* DURATIONS: the price list shows the treatment time from the service NAME
|
||||||
|
* (50 / 80 / 110 min). services.service_time holds the longer BOOKED slot
|
||||||
|
* (60 / 90 / 120 min) which covers changing and payment, and is never
|
||||||
|
* rendered to the guest. See prices_note below.
|
||||||
|
*
|
||||||
|
* Still a placeholder: assets/img/massage/masseur.png (therapist portrait),
|
||||||
|
* assets/img/massage/banner.jpg and map.jpg.
|
||||||
|
* -------------------------------------------------------------------- */
|
||||||
|
?>
|
||||||
|
<!-- Banner -->
|
||||||
|
<section id="banner">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/banner.jpg" style="width: 100%;" />
|
||||||
|
</section>
|
||||||
|
<section id="mobil-menu">
|
||||||
|
<div class="mobil-menucont">
|
||||||
|
<ul>
|
||||||
|
<li class="mobil-menu-book"><a href="<?php echo SITEURL;?>no/booking/massage">BESTILL TIME</a></li>
|
||||||
|
<li class=""><a href="<?php echo $vertical['facebook'];?>" class="icon brands fa-facebook-f"><span class="label">Facebook</span></a></li>
|
||||||
|
<li class=""><a href="<?php echo $vertical['instagram'];?>" class="icon brands fa-instagram"><span class="label">Instagram</span></a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- About Us -->
|
||||||
|
<section id="aboutus" class="wrapper style1">
|
||||||
|
<div class="container">
|
||||||
|
<div class="inner">
|
||||||
|
<header class="major">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/ollo_rose.png">
|
||||||
|
<h2>Om oss</h2>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<?php /* Owner block, lifted verbatim from beauty-form-<lang>.php at
|
||||||
|
generation time so all three verticals introduce Evelin
|
||||||
|
identically. Do not edit here - edit the beauty file and
|
||||||
|
regenerate, or the two will drift. */ ?>
|
||||||
|
<div class="bemutatkozas">
|
||||||
|
<div class="bem-bal">
|
||||||
|
<p>
|
||||||
|
Mitt navn er Evelin Bence, lederen og skaperen av Studio Beve. Jeg anser det som
|
||||||
|
viktig at våre gjester under oppholdet hos oss – mens de stenger ute litt av støyen
|
||||||
|
fra omverdenen – kan lade sine batterier og kan vende tilbake til hverdagen
|
||||||
|
forskjønnet både innvendig og utvendig.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Kvalitetstid, maksimal oppmerksomhet, de mest profesjonelle verktøyene, hånd
|
||||||
|
i hånd med profesjonalitet og kompetanse, utgjør grunnlaget for vår filosofi og våre
|
||||||
|
tjenester.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Jeg mener at skjønnhet, mote og trend ikke er kjønnsspesifikke, og hos oss har
|
||||||
|
derfor alle mulighet til å bli vakrere på ett sted, uavhengig av kjønn. Hos Studio
|
||||||
|
Beve Barber, Studio Beve Beauty og Studio Beve Massasje kan dere finne de tjenestene som er riktige
|
||||||
|
for dere.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Med nesten 10 års erfaring fra skjønnhetsindustrien, inkludert mange års
|
||||||
|
internasjonal erfaring, tenkte jeg det var på tide å åpne mitt eget studio her i
|
||||||
|
Trondheim i Innheredsveien 92, hvor gjestene har mulighet til å parkere gratis
|
||||||
|
under behandlingene.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Det er en ekstra glede for meg at jeg klarte å finne et tradisjonelt sted hvor det
|
||||||
|
allerede var en skjønnhetssalong på 50-tallet. Derfor har jeg nå muligheten til å
|
||||||
|
videreføre denne tradisjonen i et moderne miljø.
|
||||||
|
Bli vakker hos oss. Vi ser frem til å ønske deg velkommen.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="bem-jobb">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/evelin_beauty.JPG">
|
||||||
|
<h4>Evelin Bence <br> <span>Eieren, Studio Beve</span></h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php /* Therapist sub-section, following the per-worker pattern
|
||||||
|
barber/beauty use: circular portrait + name, then the bio
|
||||||
|
with a photo strip alongside. */ ?>
|
||||||
|
<div class="dolgozo-nev">
|
||||||
|
<hr>
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/vincent/vincent.jpg" class="dolgozo-kep">
|
||||||
|
<h4>VINCENT Pusch <span>- Massør</span></h4>
|
||||||
|
</div>
|
||||||
|
<div class="bemutatkozas-dolgozo">
|
||||||
|
<div class="bem-dolgozo-bal">
|
||||||
|
<p>Min interesse for massasje, manuelle behandlingsteknikker og hvordan menneskekroppen fungerer, har fulgt meg siden 2011 og har gjennom årene blitt en sentral del av min faglige karriere.</p>
|
||||||
|
<p>Jeg tok min fysioterapiutdanning i Tyskland. Jeg startet yrkeskarrieren min ved et militærsykehus, hvor jeg arbeidet som fysioterapeut og manuellterapeut. Senere fortsatte jeg arbeidet ved en tverrfaglig klinikk, før jeg etablerte og drev min egen private praksis i Tyskland frem til jeg flyttet til Norge.</p>
|
||||||
|
<p>Gjennom årene har jeg kontinuerlig utvidet min faglige kunnskap og erfaring. I tillegg til fysioterapi og manuellterapi har jeg arbeidet med idrettsfysioterapi, og siden 2019 også med kraniosakralterapi og osteopati. Kontinuerlig faglig utvikling og det å lære nye metoder er viktig for meg.</p>
|
||||||
|
<p>Jeg tror på at hvert menneske og hver kropp er forskjellig, og derfor tar jeg alltid utgangspunkt i den enkeltes behov og mål i behandlingene mine. Jeg velger og kombinerer ulike massasje- og manuelle teknikker ut fra dette, enten målet er avslapning, å redusere muskelspenninger som følge av daglig eller fysisk belastning, restitusjon etter trening eller rett og slett å gi kroppen tid til å hente seg inn.</p>
|
||||||
|
<p>Jeg har bodd i Trondheim siden mai 2026. Prosessen med norsk godkjenning av min utenlandske fysioterapiutdanning pågår for tiden. Hos Studio Beve arbeider jeg i dag som massør og tilbyr massasje og andre manuelle behandlinger som ikke krever norsk autorisasjon som helsepersonell. Når norsk autorisasjon foreligger, vil min faglige virksomhet og behandlingstilbudet jeg kan tilby, kunne utvides ytterligere.</p>
|
||||||
|
<p>Jeg gleder meg til å bli kjent med Studio Beves kunder og til å bruke min faglige erfaring til å tilby individuelt tilpassede og omsorgsfulle behandlinger.</p>
|
||||||
|
</div>
|
||||||
|
<div class="bem-dolgozo-jobb">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/vincent/1.jpg">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/vincent/2.jpg">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/vincent/3.jpg">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/vincent/4.jpg">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Treatments -->
|
||||||
|
<section id="treatments" class="wrapper style2">
|
||||||
|
<div class="container">
|
||||||
|
<div class="inner">
|
||||||
|
<header class="major">
|
||||||
|
<img src="<?php echo base_url();?>assets/img/massage/ollo_rose.png">
|
||||||
|
<h2 class="nyitva">Behandlinger</h2>
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
<div class="service-block">
|
||||||
|
<div class="service-area">
|
||||||
|
<div class="one-third service-part1">
|
||||||
|
<div class="service-inner">
|
||||||
|
<div class="service service1">
|
||||||
|
<div class="service-text service-text1">
|
||||||
|
<div class="service-icon icon1"></div>
|
||||||
|
<div class="service-content">
|
||||||
|
<div class="main-title">Klassisk svensk massasje</div>
|
||||||
|
<div class="sub-title-serv">helkropp, avslapning og velvære</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="service-text service-text2">
|
||||||
|
<div class="service-icon icon2"></div>
|
||||||
|
<div class="service-content">
|
||||||
|
<div class="main-title">Sportsmassasje</div>
|
||||||
|
<div class="sub-title-serv">for aktive personer og idrettsutøvere</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="service-text service-text3">
|
||||||
|
<div class="service-icon icon3"></div>
|
||||||
|
<div class="service-content">
|
||||||
|
<div class="main-title">Deep Tissue-massasje</div>
|
||||||
|
<div class="sub-title-serv">dypere muskulatur og bindevev</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="one-third service-part2">
|
||||||
|
<div class="service-inner">
|
||||||
|
<div class="service service2">
|
||||||
|
<a href="<?php echo SITEURL;?>no/booking/massage" class="banner-anchor"><img src="<?php echo base_url();?>assets/img/service-banner-massage.png" alt="massage" class="banner-image1"></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="one-third service-part3">
|
||||||
|
<div class="service-inner">
|
||||||
|
<div class="service service3">
|
||||||
|
<div class="service-text service-text1">
|
||||||
|
<div class="service-icon icon1"></div>
|
||||||
|
<div class="service-content">
|
||||||
|
<div class="main-title">Arbeidsmassasje</div>
|
||||||
|
<div class="sub-title-serv">kontor og fysisk arbeid</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="service-text service-text2">
|
||||||
|
<div class="service-icon icon2"></div>
|
||||||
|
<div class="service-content">
|
||||||
|
<div class="main-title">Studio Beve Signature</div>
|
||||||
|
<div class="sub-title-serv">individuelt tilpasset behandling</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="service-text service-text3">
|
||||||
|
<div class="service-icon icon3"></div>
|
||||||
|
<div class="service-content">
|
||||||
|
<div class="main-title">Kraniosakral behandling</div>
|
||||||
|
<div class="sub-title-serv">skånsom, helhetlig manuell behandling</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Prices -->
|
||||||
|
<section id="one" class="wrapper style1">
|
||||||
|
<div class="container">
|
||||||
|
<div class="inner">
|
||||||
|
<header class="major">
|
||||||
|
<img src="<?php echo SITEURL;?>assets/img/massage/ollo_rose.png">
|
||||||
|
<h2>Priser</h2>
|
||||||
|
<h4 class="prices-note">Oppgitt behandlingstid er ren behandlingstid. Timen som reserveres er noe lengre, slik at det er tid til av- og påkledning og betaling.</h4>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Grouped by treatment type. Two deliberate differences from the
|
||||||
|
* barber/beauty price lists, both because massage sells the SAME
|
||||||
|
* treatment at two or three lengths:
|
||||||
|
*
|
||||||
|
* 1. The description is printed ONCE per group rather than once
|
||||||
|
* per duration, so a three-length treatment does not repeat
|
||||||
|
* its blurb three times.
|
||||||
|
* 2. The row label is the duration alone. services.service_name
|
||||||
|
* has to stay self-describing ("Klassisk svensk massasje -
|
||||||
|
* 50 min") because the booking form and the confirmation
|
||||||
|
* email render it with no category around it - but here the
|
||||||
|
* category heading is directly above, so repeating it just
|
||||||
|
* makes every row wrap.
|
||||||
|
*
|
||||||
|
* $services arrives ordered by service_id and the catalogue is
|
||||||
|
* inserted grouped, so a simple change-detect is enough.
|
||||||
|
*/
|
||||||
|
$prevousCategory = '';
|
||||||
|
|
||||||
|
if(is_array($services)){
|
||||||
|
foreach($services as $serviceItem){
|
||||||
|
if($serviceItem->service_category != $prevousCategory){
|
||||||
|
if($prevousCategory !== ''){
|
||||||
|
echo '<div style="clear:both;"></div>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<div class="prices-category" style="width: 100%">
|
||||||
|
<h4><?php echo $serviceItem->service_category;?></h4>
|
||||||
|
<p class="category-intro"><?php echo $serviceItem->service_description;?></p>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same rule as the booking form: the category heading is
|
||||||
|
// directly above, so the row need not repeat it.
|
||||||
|
$rowLabel = vertical_service_label($vertical, $serviceItem);
|
||||||
|
?>
|
||||||
|
<div class="one-half">
|
||||||
|
<div class="category-content">
|
||||||
|
<div class="category-text-left">
|
||||||
|
<div class="main-title"><a><?php echo $rowLabel;?></a></div>
|
||||||
|
</div>
|
||||||
|
<div class="category-text-right">
|
||||||
|
<div class="price">kr <?php echo $serviceItem->service_price;?></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
$prevousCategory = $serviceItem->service_category;
|
||||||
|
}
|
||||||
|
echo '<div style="clear:both;"></div>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Opening hours -->
|
||||||
|
<section id="two" class="wrapper style2">
|
||||||
|
<div class="container">
|
||||||
|
<div class="inner">
|
||||||
|
<header class="major">
|
||||||
|
<img src="<?php echo SITEURL;?>assets/img/massage/ollo_rose.png">
|
||||||
|
<h2 class="nyitva">Åpningstider</h2>
|
||||||
|
<h4>Gratis kunderparking under behandlingen</h4>
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
<div class="nyitvatartas">
|
||||||
|
<div class="about-content">
|
||||||
|
<div class="about-text-left">
|
||||||
|
<div class="title">Ukedager</div>
|
||||||
|
</div>
|
||||||
|
<div class="about-text-right">
|
||||||
|
<div class="time">10:00 - 18:00</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="about-content">
|
||||||
|
<div class="about-text-left">
|
||||||
|
<div class="title">Lørdag</div>
|
||||||
|
</div>
|
||||||
|
<div class="about-text-right">
|
||||||
|
<div class="time">10:00 - 16:00</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="about-content">
|
||||||
|
<div class="about-text-left">
|
||||||
|
<div class="title">Søndag</div>
|
||||||
|
</div>
|
||||||
|
<div class="about-text-right">
|
||||||
|
<div class="closed">Stengt</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
@@ -7,11 +7,11 @@
|
|||||||
if($firstService) $subpage = $firstService->service_type;
|
if($firstService) $subpage = $firstService->service_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($subpage == 'beauty'){
|
$vertical = vertical_get($subpage);
|
||||||
include(getcwd().'/application/views/includes/beauty-skeleton-top.php');
|
if(!$vertical){
|
||||||
} else {
|
$vertical = vertical_get('barber');
|
||||||
include(getcwd().'/application/views/includes/barber-skeleton-top.php');
|
|
||||||
}
|
}
|
||||||
|
include(getcwd().'/application/views/includes/'.$vertical['skeleton'].'-skeleton-top.php');
|
||||||
|
|
||||||
$messages = array(
|
$messages = array(
|
||||||
'no' => 'Din bestilling den <strong>'.$booking->booking_date.'</strong> kl. <strong>'.date('H:i', strtotime($booking->booking_start_time)).'</strong> med <strong>'.htmlspecialchars($worker->worker_name, ENT_QUOTES, 'UTF-8').'</strong> er avbestilt.',
|
'no' => 'Din bestilling den <strong>'.$booking->booking_date.'</strong> kl. <strong>'.date('H:i', strtotime($booking->booking_start_time)).'</strong> med <strong>'.htmlspecialchars($worker->worker_name, ENT_QUOTES, 'UTF-8').'</strong> er avbestilt.',
|
||||||
@@ -36,9 +36,5 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
if($subpage == 'beauty'){
|
include(getcwd().'/application/views/includes/'.$vertical['skeleton'].'-skeleton-bottom.php');
|
||||||
include(getcwd().'/application/views/includes/beauty-skeleton-bottom.php');
|
|
||||||
} else {
|
|
||||||
include(getcwd().'/application/views/includes/barber-skeleton-bottom.php');
|
|
||||||
}
|
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
if($subpage == 'beauty'){
|
// Skeleton comes from the vertical registry so a new vertical needs no
|
||||||
include(getcwd().'/application/views/includes/beauty-skeleton-top.php');
|
// edit here. barber/beauty still resolve to their own skeleton files.
|
||||||
} else {
|
$vertical = isset($vertical) ? $vertical : vertical_get($subpage);
|
||||||
include(getcwd().'/application/views/includes/barber-skeleton-top.php');
|
if(!$vertical){
|
||||||
|
$vertical = vertical_get('barber');
|
||||||
}
|
}
|
||||||
|
include(getcwd().'/application/views/includes/'.$vertical['skeleton'].'-skeleton-top.php');
|
||||||
|
|
||||||
$lang = $selectedLang;
|
$lang = $selectedLang;
|
||||||
|
|
||||||
@@ -341,8 +343,8 @@
|
|||||||
$isOtherCategory = ($categorySlug !== '' && $serviceItem->serv_cat_slug !== $categorySlug);
|
$isOtherCategory = ($categorySlug !== '' && $serviceItem->serv_cat_slug !== $categorySlug);
|
||||||
?>
|
?>
|
||||||
<div class="serviceRow">
|
<div class="serviceRow">
|
||||||
<div class="serviceCol serviceNameCol" id="serviceName_<?php echo $serviceItem->service_id; ?>">
|
<div class="serviceCol serviceNameCol" id="serviceName_<?php echo $serviceItem->service_id; ?>" data-service-name="<?php echo htmlspecialchars($serviceItem->service_name, ENT_QUOTES, 'UTF-8'); ?>">
|
||||||
<?php echo htmlspecialchars($serviceItem->service_name); ?>
|
<?php echo htmlspecialchars(vertical_service_label(isset($vertical) ? $vertical : NULL, $serviceItem)); ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="serviceCol">
|
<div class="serviceCol">
|
||||||
<input type="time" class="serviceTime" id="time_<?php echo $serviceItem->service_id; ?>" value="<?php echo $serviceItem->service_time; ?>"/>
|
<input type="time" class="serviceTime" id="time_<?php echo $serviceItem->service_id; ?>" value="<?php echo $serviceItem->service_time; ?>"/>
|
||||||
@@ -462,6 +464,19 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
$('.service').click(function(){
|
$('.service').click(function(){
|
||||||
|
<?php if ( ! empty($vertical['single_service_booking'])): ?>
|
||||||
|
/* See booking-form-*.php: one treatment at a time for this vertical. */
|
||||||
|
if($(this).is(':checked')){
|
||||||
|
$('.service').not(this)
|
||||||
|
.prop('checked', false)
|
||||||
|
.prop('disabled', true)
|
||||||
|
.closest('.serviceRow').addClass('serviceRowDisabled');
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$('.service').prop('disabled', false);
|
||||||
|
$('.serviceRow').removeClass('serviceRowDisabled');
|
||||||
|
}
|
||||||
|
<?php endif; ?>
|
||||||
recalcServices();
|
recalcServices();
|
||||||
if($('.service').is(':checked')){
|
if($('.service').is(':checked')){
|
||||||
var selectedClasses = $(this).attr('class');
|
var selectedClasses = $(this).attr('class');
|
||||||
@@ -500,7 +515,9 @@
|
|||||||
var selected_id = $(this).attr('id');
|
var selected_id = $(this).attr('id');
|
||||||
var priceEl = document.getElementById('servicePrice_'+selected_id).innerHTML.trim();
|
var priceEl = document.getElementById('servicePrice_'+selected_id).innerHTML.trim();
|
||||||
totalPrice += parseInt(priceEl);
|
totalPrice += parseInt(priceEl);
|
||||||
var nameEl = document.getElementById('serviceName_'+selected_id).innerHTML.trim();
|
var nameNode = document.getElementById('serviceName_'+selected_id);
|
||||||
|
// Prefer the full name; the visible label may be abbreviated.
|
||||||
|
var nameEl = (nameNode.getAttribute('data-service-name') || nameNode.innerHTML).trim();
|
||||||
selectedServices += '<div class="totalServiceRow"><div class="selectedServiceCol totalSelectedServiceName">'+nameEl+'</div><div class="selectedServiceCol totalSelectedServicePrice">'+priceEl+' kr</div></div>';
|
selectedServices += '<div class="totalServiceRow"><div class="selectedServiceCol totalSelectedServiceName">'+nameEl+'</div><div class="selectedServiceCol totalSelectedServicePrice">'+priceEl+' kr</div></div>';
|
||||||
|
|
||||||
var currentTotal = $('#servicelength').val();
|
var currentTotal = $('#servicelength').val();
|
||||||
@@ -632,9 +649,5 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
if($subpage == 'beauty'){
|
include(getcwd().'/application/views/includes/'.$vertical['skeleton'].'-skeleton-bottom.php');
|
||||||
include(getcwd().'/application/views/includes/beauty-skeleton-bottom.php');
|
|
||||||
} else {
|
|
||||||
include(getcwd().'/application/views/includes/barber-skeleton-bottom.php');
|
|
||||||
}
|
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Generic booking error page.
|
||||||
|
*/
|
||||||
|
include(getcwd().'/application/views/includes/vertical-skeleton-top.php');
|
||||||
|
|
||||||
|
$lang = vertical_lang($selectedLang);
|
||||||
|
include(getcwd().'/application/views/pages/includes/booking-error-form-'.$lang.'.php');
|
||||||
|
|
||||||
|
include(getcwd().'/application/views/includes/vertical-skeleton-bottom.php');
|
||||||
|
?>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Generic "booking finished" page.
|
||||||
|
*/
|
||||||
|
include(getcwd().'/application/views/includes/vertical-skeleton-top.php');
|
||||||
|
|
||||||
|
$lang = vertical_lang($selectedLang);
|
||||||
|
include(getcwd().'/application/views/pages/includes/booking-finished-form-'.$lang.'.php');
|
||||||
|
|
||||||
|
include(getcwd().'/application/views/includes/vertical-skeleton-bottom.php');
|
||||||
|
?>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Generic booking page. The booking form partial is already shared between
|
||||||
|
* barber and beauty, so only the skeleton is parameterised here.
|
||||||
|
*/
|
||||||
|
include(getcwd().'/application/views/includes/vertical-skeleton-top.php');
|
||||||
|
|
||||||
|
$lang = vertical_lang($selectedLang);
|
||||||
|
include(getcwd().'/application/views/pages/includes/booking-form-'.$lang.'.php');
|
||||||
|
|
||||||
|
include(getcwd().'/application/views/includes/vertical-skeleton-bottom.php');
|
||||||
|
?>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Generic vertical landing page.
|
||||||
|
*
|
||||||
|
* Expects $vertical and $selectedLang. Mirrors pages/beauty.php, but the
|
||||||
|
* content partial is chosen from the registry slug rather than hardcoded,
|
||||||
|
* so a new vertical needs three content files and no new dispatcher.
|
||||||
|
*/
|
||||||
|
include(getcwd().'/application/views/includes/vertical-skeleton-top.php');
|
||||||
|
|
||||||
|
$lang = vertical_lang($selectedLang);
|
||||||
|
$contentFile = getcwd().'/application/views/pages/includes/'.$vertical['slug'].'-form-'.$lang.'.php';
|
||||||
|
|
||||||
|
if(file_exists($contentFile)){
|
||||||
|
include($contentFile);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
include(getcwd().'/application/views/pages/includes/'.$vertical['slug'].'-form-en.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
include(getcwd().'/application/views/includes/vertical-skeleton-bottom.php');
|
||||||
|
?>
|
||||||
@@ -5136,6 +5136,8 @@ input, select, textarea {
|
|||||||
|
|
||||||
.tiles {
|
.tiles {
|
||||||
|
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
display: -moz-flex;
|
display: -moz-flex;
|
||||||
|
|
||||||
display: -webkit-flex;
|
display: -webkit-flex;
|
||||||
@@ -5176,7 +5178,7 @@ input, select, textarea {
|
|||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
width: 40%;
|
width: 28%;
|
||||||
|
|
||||||
/* width: calc(33.33333% - 2.5em); */
|
/* width: calc(33.33333% - 2.5em); */
|
||||||
|
|
||||||
@@ -5190,7 +5192,9 @@ input, select, textarea {
|
|||||||
|
|
||||||
.tiles article:hover {
|
.tiles article:hover {
|
||||||
|
|
||||||
background: #9e8462;
|
/* per-vertical hover fill lives on .style1/.style2/.style3 below;
|
||||||
|
|
||||||
|
this used to hardcode barber gold for any tile without a style class */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5204,9 +5208,9 @@ input, select, textarea {
|
|||||||
|
|
||||||
border-radius: 50px;
|
border-radius: 50px;
|
||||||
|
|
||||||
margin-right: 0;
|
margin-right: 1.5em;
|
||||||
|
|
||||||
margin-left: 5em;
|
margin-left: 1.5em;
|
||||||
|
|
||||||
-moz-transition: background 0.2s ease-in-out;
|
-moz-transition: background 0.2s ease-in-out;
|
||||||
|
|
||||||
@@ -5226,9 +5230,9 @@ input, select, textarea {
|
|||||||
|
|
||||||
background: #000;
|
background: #000;
|
||||||
|
|
||||||
margin-left: 0;
|
margin-left: 1.5em;
|
||||||
|
|
||||||
margin-right: 5em;
|
margin-right: 1.5em;
|
||||||
|
|
||||||
border-radius: 50px;
|
border-radius: 50px;
|
||||||
|
|
||||||
@@ -5246,6 +5250,32 @@ input, select, textarea {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* massage vertical */
|
||||||
|
|
||||||
|
.tiles article.style3{
|
||||||
|
|
||||||
|
background: #000;
|
||||||
|
|
||||||
|
margin-left: 1.5em;
|
||||||
|
|
||||||
|
margin-right: 1.5em;
|
||||||
|
|
||||||
|
border-radius: 50px;
|
||||||
|
|
||||||
|
border: 10px solid #9bbfae;
|
||||||
|
|
||||||
|
-moz-transition: background 0.2s ease-in-out;
|
||||||
|
|
||||||
|
-webkit-transition: background 0.2s ease-in-out;
|
||||||
|
|
||||||
|
-ms-transition: background 0.2s ease-in-out;
|
||||||
|
|
||||||
|
transition: background 0.2s ease-in-out;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.tiles article.style1:hover{
|
.tiles article.style1:hover{
|
||||||
|
|
||||||
background: #E4AD9C;
|
background: #E4AD9C;
|
||||||
@@ -5262,6 +5292,14 @@ input, select, textarea {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.tiles article.style3:hover{
|
||||||
|
|
||||||
|
background: #9bbfae;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.tiles article > .image {
|
.tiles article > .image {
|
||||||
|
|
||||||
-moz-transition: -moz-transform 0.5s ease;
|
-moz-transition: -moz-transform 0.5s ease;
|
||||||
@@ -5464,10 +5502,24 @@ input, select, textarea {
|
|||||||
|
|
||||||
.tiles article > a h2 {
|
.tiles article > a h2 {
|
||||||
|
|
||||||
font-size: 52px;
|
/* Was 52px, chosen when there were two 40%-wide tiles with
|
||||||
|
|
||||||
|
six-letter labels. Tiles are now 28% wide and MASSAGE is
|
||||||
|
|
||||||
|
eight letters, which pushed the word out past the rounded
|
||||||
|
|
||||||
|
border. 42px plus side padding keeps the longest label
|
||||||
|
|
||||||
|
clear of the corner radius on all three tiles. */
|
||||||
|
|
||||||
|
font-size: 42px;
|
||||||
|
|
||||||
font-family: 'Abril Fatface', cursive;
|
font-family: 'Abril Fatface', cursive;
|
||||||
|
|
||||||
|
padding: 0 0.35em;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -5530,6 +5582,18 @@ input, select, textarea {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.tiles article.style3 > .image:before {
|
||||||
|
|
||||||
|
background-size: cover;
|
||||||
|
|
||||||
|
background-image: url(../../assets/img/massage.jpg);
|
||||||
|
|
||||||
|
background-color: #5f7d6e;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
body:not(.is-touch) .tiles article:hover > .image {
|
body:not(.is-touch) .tiles article:hover > .image {
|
||||||
|
|
||||||
-moz-transform: scale(1.1);
|
-moz-transform: scale(1.1);
|
||||||
@@ -6814,21 +6878,25 @@ input, select, textarea {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
.tiles article.style1 {
|
/* .style1 used to be position:absolute; right:0 here - a two-tile-only
|
||||||
|
|
||||||
position: absolute;
|
centring trick that overlapped the moment a third tile existed.
|
||||||
|
|
||||||
right: 0;
|
Normal flex flow handles any tile count. */
|
||||||
|
|
||||||
margin-left: 0;
|
.tiles article.style1,
|
||||||
|
|
||||||
|
.tiles article.style2,
|
||||||
|
|
||||||
|
.tiles article.style3 {
|
||||||
|
|
||||||
}
|
position: relative;
|
||||||
|
|
||||||
.tiles article.style2 {
|
width: 28%;
|
||||||
|
|
||||||
margin-right: 0;
|
margin-left: 1em;
|
||||||
|
|
||||||
|
margin-right: 1em;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6888,7 +6956,7 @@ input, select, textarea {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
.tiles article.style1, .tiles article.style2{
|
.tiles article.style1, .tiles article.style2, .tiles article.style3{
|
||||||
|
|
||||||
border-radius: 35px;
|
border-radius: 35px;
|
||||||
|
|
||||||
@@ -6896,6 +6964,8 @@ input, select, textarea {
|
|||||||
|
|
||||||
margin-right: 2em;
|
margin-right: 2em;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -6918,6 +6988,14 @@ input, select, textarea {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.tiles article.style3{
|
||||||
|
|
||||||
|
border: 7px solid #9bbfae;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 87 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,73 @@
|
|||||||
|
-- ============================================================================
|
||||||
|
-- Massage vertical - REAL catalogue and therapist (replaces the demo data)
|
||||||
|
-- ============================================================================
|
||||||
|
-- Studio Beve, 2026-08-13.
|
||||||
|
--
|
||||||
|
-- DISPLAY vs BOOKING DURATION
|
||||||
|
-- ---------------------------
|
||||||
|
-- The guest-facing duration is in the service NAME: 50 / 80 / 110 min.
|
||||||
|
-- services.service_time is the BOOKED slot: 60 / 90 / 120 min, which adds
|
||||||
|
-- changing and payment time. The two intentionally differ.
|
||||||
|
--
|
||||||
|
-- service_time never reaches the guest: the booking form's duration input is
|
||||||
|
-- .serviceTime { display: none; }, and the price list, the booking form and
|
||||||
|
-- the confirmation email all render service_name. The email's
|
||||||
|
-- "start - finish" window correctly shows the full reserved slot.
|
||||||
|
--
|
||||||
|
-- Prices: 50 min = 1050, 80 min = 1575, 110 min = 2050 NOK.
|
||||||
|
--
|
||||||
|
-- Order matters: the landing-page price list groups by service_category and
|
||||||
|
-- only prints a heading when it changes, iterating service_id ASC. Rows are
|
||||||
|
-- therefore inserted grouped by treatment type.
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
|
||||||
|
SET @cat := (SELECT service_category_id FROM service_categories
|
||||||
|
WHERE serv_cat_slug = 'massage' AND is_deleted = 0 LIMIT 1);
|
||||||
|
SET @worker := (SELECT worker_id FROM workers
|
||||||
|
WHERE service_category_id = @cat AND is_deleted = 0 LIMIT 1);
|
||||||
|
SELECT @cat AS massage_category_id, @worker AS masseur_worker_id;
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------- therapist
|
||||||
|
UPDATE workers
|
||||||
|
SET worker_name = 'Vincent Pusch',
|
||||||
|
worker_profile_img = 'worker_Vincent_Pusch.jpg'
|
||||||
|
WHERE worker_id = @worker;
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------- catalogue
|
||||||
|
-- The four placeholder services are removed outright: no booking references
|
||||||
|
-- them (verified zero bookings for this worker), so there is nothing to
|
||||||
|
-- preserve with a soft delete.
|
||||||
|
DELETE FROM services WHERE service_category_id = @cat;
|
||||||
|
|
||||||
|
INSERT INTO services (
|
||||||
|
service_type,
|
||||||
|
service_category_no, service_category_en, service_category_hu,
|
||||||
|
service_name_no, service_name_en, service_name_hu,
|
||||||
|
service_description_no, service_description_en, service_description_hu,
|
||||||
|
service_price, service_time, service_category_id, is_enabled, is_deleted
|
||||||
|
) VALUES
|
||||||
|
('massage', 'Klassisk svensk massasje', 'Classic Swedish Massage', 'Klasszikus svédmasszázs', 'Klassisk svensk massasje – 50 min', 'Classic Swedish Massage – 50 min', 'Klasszikus svédmasszázs – 50 perc', 'En behagelig helkroppsmassasje som bidrar til å løsne opp spenninger i muskulaturen, redusere hverdagens stress og fremme avslapning og velvære.', 'A relaxing full-body massage designed to ease muscle tension, reduce everyday stress and promote relaxation and well-being.', 'Kellemes, teljes testet átmozgató masszázs, amely segít ellazítani az izmokat, csökkenteni a mindennapi feszültséget és támogatja a testi-lelki kikapcsolódást.', 1050, '01:00:00', @cat, 1, 0),
|
||||||
|
('massage', 'Klassisk svensk massasje', 'Classic Swedish Massage', 'Klasszikus svédmasszázs', 'Klassisk svensk massasje – 80 min', 'Classic Swedish Massage – 80 min', 'Klasszikus svédmasszázs – 80 perc', 'En behagelig helkroppsmassasje som bidrar til å løsne opp spenninger i muskulaturen, redusere hverdagens stress og fremme avslapning og velvære.', 'A relaxing full-body massage designed to ease muscle tension, reduce everyday stress and promote relaxation and well-being.', 'Kellemes, teljes testet átmozgató masszázs, amely segít ellazítani az izmokat, csökkenteni a mindennapi feszültséget és támogatja a testi-lelki kikapcsolódást.', 1575, '01:30:00', @cat, 1, 0),
|
||||||
|
('massage', 'Klassisk svensk massasje', 'Classic Swedish Massage', 'Klasszikus svédmasszázs', 'Klassisk svensk massasje – 110 min', 'Classic Swedish Massage – 110 min', 'Klasszikus svédmasszázs – 110 perc', 'En behagelig helkroppsmassasje som bidrar til å løsne opp spenninger i muskulaturen, redusere hverdagens stress og fremme avslapning og velvære.', 'A relaxing full-body massage designed to ease muscle tension, reduce everyday stress and promote relaxation and well-being.', 'Kellemes, teljes testet átmozgató masszázs, amely segít ellazítani az izmokat, csökkenteni a mindennapi feszültséget és támogatja a testi-lelki kikapcsolódást.', 2050, '02:00:00', @cat, 1, 0),
|
||||||
|
('massage', 'Sportsmassasje', 'Sports Massage', 'Sportmasszázs', 'Sportsmassasje – 50 min', 'Sports Massage – 50 min', 'Sportmasszázs – 50 perc', 'En målrettet massasje for aktive personer og idrettsutøvere. Behandlingen tilpasses individuelle behov og kan kombinere ulike teknikker som fascia- og triggerpunktteknikker, myofascial release, PNF, kopping, flossing eller taping.', 'A targeted massage for active individuals and athletes. The treatment is adapted to individual needs and may combine techniques such as fascia and trigger point techniques, myofascial release, PNF, cupping, flossing or taping.', 'Aktív életmódot folytatók és sportolók számára kialakított célzott masszázs. A kezelés az igényekhez igazodva különböző technikákat kombinálhat, például fascia- és triggerponttechnikákat, myofascial release-t, PNF-et, köpölyözést, flossingot vagy tapinget.', 1050, '01:00:00', @cat, 1, 0),
|
||||||
|
('massage', 'Sportsmassasje', 'Sports Massage', 'Sportmasszázs', 'Sportsmassasje – 80 min', 'Sports Massage – 80 min', 'Sportmasszázs – 80 perc', 'En målrettet massasje for aktive personer og idrettsutøvere. Behandlingen tilpasses individuelle behov og kan kombinere ulike teknikker som fascia- og triggerpunktteknikker, myofascial release, PNF, kopping, flossing eller taping.', 'A targeted massage for active individuals and athletes. The treatment is adapted to individual needs and may combine techniques such as fascia and trigger point techniques, myofascial release, PNF, cupping, flossing or taping.', 'Aktív életmódot folytatók és sportolók számára kialakított célzott masszázs. A kezelés az igényekhez igazodva különböző technikákat kombinálhat, például fascia- és triggerponttechnikákat, myofascial release-t, PNF-et, köpölyözést, flossingot vagy tapinget.', 1575, '01:30:00', @cat, 1, 0),
|
||||||
|
('massage', 'Deep Tissue-massasje', 'Deep Tissue Massage', 'Mélyszöveti masszázs', 'Deep Tissue-massasje – 50 min', 'Deep Tissue Massage – 50 min', 'Mélyszöveti masszázs – 50 perc', 'En mer intensiv massasje med fokus på dypere muskulatur og bindevev. Behandlingen har som mål å løsne vedvarende muskelspenninger, støtte bevegeligheten og arbeide målrettet med belastede områder.', 'A more intensive massage focusing on deeper muscles and connective tissue. It is designed to release persistent muscle tension, support mobility and target areas affected by physical strain.', 'Intenzívebb kezelés, amely a mélyebben fekvő izmokra és kötőszövetekre koncentrál. Célja a tartós izomfeszültség oldása, a mobilitás támogatása és a túlterhelt területek célzott kezelése.', 1050, '01:00:00', @cat, 1, 0),
|
||||||
|
('massage', 'Deep Tissue-massasje', 'Deep Tissue Massage', 'Mélyszöveti masszázs', 'Deep Tissue-massasje – 80 min', 'Deep Tissue Massage – 80 min', 'Mélyszöveti masszázs – 80 perc', 'En mer intensiv massasje med fokus på dypere muskulatur og bindevev. Behandlingen har som mål å løsne vedvarende muskelspenninger, støtte bevegeligheten og arbeide målrettet med belastede områder.', 'A more intensive massage focusing on deeper muscles and connective tissue. It is designed to release persistent muscle tension, support mobility and target areas affected by physical strain.', 'Intenzívebb kezelés, amely a mélyebben fekvő izmokra és kötőszövetekre koncentrál. Célja a tartós izomfeszültség oldása, a mobilitás támogatása és a túlterhelt területek célzott kezelése.', 1575, '01:30:00', @cat, 1, 0),
|
||||||
|
('massage', 'Arbeidsmassasje – kontor og fysisk arbeid', 'Work Recovery Massage – Office & Physical Work', 'Irodai és fizikai munka utáni masszázs', 'Arbeidsmassasje – kontor og fysisk arbeid – 50 min', 'Work Recovery Massage – Office & Physical Work – 50 min', 'Irodai és fizikai munka utáni masszázs – 50 perc', 'En massasje utviklet for spenninger som kan oppstå ved stillesittende, repetitivt eller fysisk krevende arbeid. Behandlingen fokuserer særlig på rygg, nakke, skuldre, armer og hender, og kan ved behov også inkludere hode og kjeveområdet.', 'A massage designed to relieve tension associated with sedentary, repetitive or physically demanding work. The treatment focuses primarily on the back, neck, shoulders, arms and hands, and may also include the head and jaw area when needed.', 'Ülőmunka, ismétlődő terhelés vagy fizikailag megterhelő munka után kialakuló feszültségek oldására összeállított kezelés. Elsősorban a hát, nyak, váll, kar és kéz területére koncentrál, szükség szerint a fej és az állkapocs környékének kezelésével kiegészítve.', 1050, '01:00:00', @cat, 1, 0),
|
||||||
|
('massage', 'Arbeidsmassasje – kontor og fysisk arbeid', 'Work Recovery Massage – Office & Physical Work', 'Irodai és fizikai munka utáni masszázs', 'Arbeidsmassasje – kontor og fysisk arbeid – 80 min', 'Work Recovery Massage – Office & Physical Work – 80 min', 'Irodai és fizikai munka utáni masszázs – 80 perc', 'En massasje utviklet for spenninger som kan oppstå ved stillesittende, repetitivt eller fysisk krevende arbeid. Behandlingen fokuserer særlig på rygg, nakke, skuldre, armer og hender, og kan ved behov også inkludere hode og kjeveområdet.', 'A massage designed to relieve tension associated with sedentary, repetitive or physically demanding work. The treatment focuses primarily on the back, neck, shoulders, arms and hands, and may also include the head and jaw area when needed.', 'Ülőmunka, ismétlődő terhelés vagy fizikailag megterhelő munka után kialakuló feszültségek oldására összeállított kezelés. Elsősorban a hát, nyak, váll, kar és kéz területére koncentrál, szükség szerint a fej és az állkapocs környékének kezelésével kiegészítve.', 1575, '01:30:00', @cat, 1, 0),
|
||||||
|
('massage', 'Studio Beve Signature – individuelt tilpasset massasje', 'Studio Beve Signature – Personalized Massage', 'Studio Beve Signature – személyre szabott masszázs', 'Studio Beve Signature – individuelt tilpasset massasje – 50 min', 'Studio Beve Signature – Personalized Massage – 50 min', 'Studio Beve Signature – személyre szabott masszázs – 50 perc', 'En individuelt tilpasset behandling for deg som ønsker en massasje basert på dine egne behov og mål. Etter en kort samtale velger og kombinerer massøren egnede massasje- og manuelle teknikker.', 'A fully personalized treatment tailored to your individual needs and goals. Following a brief consultation, the massage therapist selects and combines suitable massage and manual techniques.', 'Teljesen személyre szabott kezelés azok számára, akik egyéni igényeikhez és céljaikhoz igazított masszázst szeretnének. A masszőr a vendéggel történő rövid egyeztetés alapján választja ki és kombinálja a megfelelő masszázs- és manuális technikákat.', 1050, '01:00:00', @cat, 1, 0),
|
||||||
|
('massage', 'Studio Beve Signature – individuelt tilpasset massasje', 'Studio Beve Signature – Personalized Massage', 'Studio Beve Signature – személyre szabott masszázs', 'Studio Beve Signature – individuelt tilpasset massasje – 80 min', 'Studio Beve Signature – Personalized Massage – 80 min', 'Studio Beve Signature – személyre szabott masszázs – 80 perc', 'En individuelt tilpasset behandling for deg som ønsker en massasje basert på dine egne behov og mål. Etter en kort samtale velger og kombinerer massøren egnede massasje- og manuelle teknikker.', 'A fully personalized treatment tailored to your individual needs and goals. Following a brief consultation, the massage therapist selects and combines suitable massage and manual techniques.', 'Teljesen személyre szabott kezelés azok számára, akik egyéni igényeikhez és céljaikhoz igazított masszázst szeretnének. A masszőr a vendéggel történő rövid egyeztetés alapján választja ki és kombinálja a megfelelő masszázs- és manuális technikákat.', 1575, '01:30:00', @cat, 1, 0),
|
||||||
|
('massage', 'Studio Beve Signature – individuelt tilpasset massasje', 'Studio Beve Signature – Personalized Massage', 'Studio Beve Signature – személyre szabott masszázs', 'Studio Beve Signature – individuelt tilpasset massasje – 110 min', 'Studio Beve Signature – Personalized Massage – 110 min', 'Studio Beve Signature – személyre szabott masszázs – 110 perc', 'En individuelt tilpasset behandling for deg som ønsker en massasje basert på dine egne behov og mål. Etter en kort samtale velger og kombinerer massøren egnede massasje- og manuelle teknikker.', 'A fully personalized treatment tailored to your individual needs and goals. Following a brief consultation, the massage therapist selects and combines suitable massage and manual techniques.', 'Teljesen személyre szabott kezelés azok számára, akik egyéni igényeikhez és céljaikhoz igazított masszázst szeretnének. A masszőr a vendéggel történő rövid egyeztetés alapján választja ki és kombinálja a megfelelő masszázs- és manuális technikákat.', 2050, '02:00:00', @cat, 1, 0),
|
||||||
|
('massage', 'Kraniosakral behandling', 'Craniosacral Treatment', 'Craniosacralis kezelés', 'Kraniosakral behandling – 50 min', 'Craniosacral Treatment – 50 min', 'Craniosacralis kezelés – 50 perc', 'En skånsom og helhetlig manuell behandling som med lette berøringer legger til rette for dyp avslapning og ro i kroppen. Behandlingen utføres med komfortable klær på.', 'A gentle, holistic manual treatment using light touch to promote deep relaxation and a sense of calm in the body. The treatment is performed while wearing comfortable clothing.', 'Gyengéd, holisztikus manuális kezelés, amely finom érintésekkel támogatja a mély relaxációt és a test ellazulását. A kezelés kényelmes ruházatban történik.', 1050, '01:00:00', @cat, 1, 0),
|
||||||
|
('massage', 'Kraniosakral behandling', 'Craniosacral Treatment', 'Craniosacralis kezelés', 'Kraniosakral behandling – 80 min', 'Craniosacral Treatment – 80 min', 'Craniosacralis kezelés – 80 perc', 'En skånsom og helhetlig manuell behandling som med lette berøringer legger til rette for dyp avslapning og ro i kroppen. Behandlingen utføres med komfortable klær på.', 'A gentle, holistic manual treatment using light touch to promote deep relaxation and a sense of calm in the body. The treatment is performed while wearing comfortable clothing.', 'Gyengéd, holisztikus manuális kezelés, amely finom érintésekkel támogatja a mély relaxációt és a test ellazulását. A kezelés kényelmes ruházatban történik.', 1575, '01:30:00', @cat, 1, 0),
|
||||||
|
('massage', 'Kraniosakral behandling', 'Craniosacral Treatment', 'Craniosacralis kezelés', 'Kraniosakral behandling – 110 min', 'Craniosacral Treatment – 110 min', 'Craniosacralis kezelés – 110 perc', 'En skånsom og helhetlig manuell behandling som med lette berøringer legger til rette for dyp avslapning og ro i kroppen. Behandlingen utføres med komfortable klær på.', 'A gentle, holistic manual treatment using light touch to promote deep relaxation and a sense of calm in the body. The treatment is performed while wearing comfortable clothing.', 'Gyengéd, holisztikus manuális kezelés, amely finom érintésekkel támogatja a mély relaxációt és a test ellazulását. A kezelés kényelmes ruházatban történik.', 2050, '02:00:00', @cat, 1, 0);
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------- verify
|
||||||
|
SELECT service_id, service_category_no, service_name_no, service_price,
|
||||||
|
service_time AS booked_slot, is_enabled
|
||||||
|
FROM services WHERE service_category_id = @cat ORDER BY service_id;
|
||||||
|
|
||||||
|
SELECT worker_id, worker_name, worker_profile_img, service_category_id
|
||||||
|
FROM workers WHERE worker_id = @worker;
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
-- ============================================================================
|
||||||
|
-- Massage vertical - data migration
|
||||||
|
-- ============================================================================
|
||||||
|
-- Studio Beve, 2026-08-10.
|
||||||
|
--
|
||||||
|
-- NOTE: there is NO DDL here. The massage vertical needed no schema change:
|
||||||
|
-- the vertical is derived from workers.service_category_id, and
|
||||||
|
-- services.service_type is already a VARCHAR. No ALTER, no backfill,
|
||||||
|
-- no UPDATE of any existing row.
|
||||||
|
--
|
||||||
|
-- ORDER IS LOAD-BEARING. Run the whole file in ONE session (it uses @vars):
|
||||||
|
--
|
||||||
|
-- 1. service_categories FIRST. getAllServiceByServiceType() and
|
||||||
|
-- getWorkersByCategorySlug() both INNER JOIN service_categories, so a
|
||||||
|
-- dangling category_id makes rows silently INVISIBLE rather than erroring.
|
||||||
|
-- 2. The worker row, carrying that category id. Must exist before any
|
||||||
|
-- massage service is enabled, or the public booking page renders an
|
||||||
|
-- empty step 2.
|
||||||
|
-- 3. worker_schedule rows for every bookable weekday. NOT OPTIONAL, and
|
||||||
|
-- worker_schedule_overrides alone are NOT sufficient - getAvailableTimes()
|
||||||
|
-- returns [] without a schedule row, and booking_process() rejects with
|
||||||
|
-- 'worker_unavailable'.
|
||||||
|
-- 4. Services inserted with is_enabled = '0'. Flipping that to '1' is the
|
||||||
|
-- go-live switch (step 9), after the smoke test.
|
||||||
|
--
|
||||||
|
-- DEMO DATA: the therapist ("Nora Lindqvist"), the four services and their
|
||||||
|
-- prices are placeholders. Replace with real values before production.
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------- 1. category
|
||||||
|
INSERT INTO service_categories (serv_cat_slug, serv_cat_name, is_deleted)
|
||||||
|
VALUES ('massage', 'Masszázs', 0);
|
||||||
|
|
||||||
|
SET @cat := LAST_INSERT_ID();
|
||||||
|
SELECT @cat AS new_service_category_id;
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------- 2. worker
|
||||||
|
-- is_beauty / is_barber are the legacy columns; nothing reads them any more
|
||||||
|
-- (the vertical is derived from service_category_id). They are NOT NULL, so
|
||||||
|
-- they are written as 0 here to stay consistent with the derived value.
|
||||||
|
INSERT INTO workers (
|
||||||
|
worker_name, worker_profile_img, worker_info,
|
||||||
|
service_category_id, is_barber, is_beauty, is_active, is_deleted,
|
||||||
|
google_calendar_id, ntfy_topic,
|
||||||
|
lunch_window_start, lunch_window_end, lunch_preferred_time
|
||||||
|
) VALUES (
|
||||||
|
'Nora Lindqvist', 'worker_Nora_Lindqvist.jpg', '',
|
||||||
|
@cat, 0, 0, 1, 0,
|
||||||
|
NULL, NULL,
|
||||||
|
'12:00:00', '14:00:00', '12:30:00'
|
||||||
|
);
|
||||||
|
|
||||||
|
SET @worker := LAST_INSERT_ID();
|
||||||
|
SELECT @worker AS new_worker_id;
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------- 3. schedule
|
||||||
|
-- weekday follows PHP date('w'): 0 = Sunday .. 6 = Saturday.
|
||||||
|
-- Mon-Fri 10:00-18:00, Sat 10:00-16:00, Sun closed (no row).
|
||||||
|
INSERT INTO worker_schedule (worker_id, weekday, start_time, end_time, is_alternate_week) VALUES
|
||||||
|
(@worker, 1, '10:00:00', '18:00:00', 0),
|
||||||
|
(@worker, 2, '10:00:00', '18:00:00', 0),
|
||||||
|
(@worker, 3, '10:00:00', '18:00:00', 0),
|
||||||
|
(@worker, 4, '10:00:00', '18:00:00', 0),
|
||||||
|
(@worker, 5, '10:00:00', '18:00:00', 0),
|
||||||
|
(@worker, 6, '10:00:00', '16:00:00', 0);
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------- 4. services
|
||||||
|
-- Inserted DISABLED. service_time drives the slot length, so it also decides
|
||||||
|
-- how many slots the therapist appears to have against the 18:00 close:
|
||||||
|
-- a 90-minute service has its last possible start at 16:30.
|
||||||
|
INSERT INTO services (
|
||||||
|
service_type,
|
||||||
|
service_category_no, service_category_en, service_category_hu,
|
||||||
|
service_name_no, service_name_en, service_name_hu,
|
||||||
|
service_description_no, service_description_en, service_description_hu,
|
||||||
|
service_price, service_time, service_category_id, is_enabled, is_deleted
|
||||||
|
) VALUES
|
||||||
|
('massage',
|
||||||
|
'Massasje', 'Massage', 'Masszázs',
|
||||||
|
'Klassisk massasje 60 min', 'Classic massage 60 min', 'Klasszikus masszázs 60 perc',
|
||||||
|
'Helkropp, avslappende', 'Full body, relaxing', 'Teljes test, lazító',
|
||||||
|
900, '01:00:00', @cat, 0, 0),
|
||||||
|
|
||||||
|
('massage',
|
||||||
|
'Massasje', 'Massage', 'Masszázs',
|
||||||
|
'Klassisk massasje 90 min', 'Classic massage 90 min', 'Klasszikus masszázs 90 perc',
|
||||||
|
'Helkropp, utvidet behandling', 'Full body, extended treatment', 'Teljes test, hosszabb kezelés',
|
||||||
|
1300, '01:30:00', @cat, 0, 0),
|
||||||
|
|
||||||
|
('massage',
|
||||||
|
'Massasje', 'Massage', 'Masszázs',
|
||||||
|
'Dypvevsmassasje 60 min', 'Deep tissue massage 60 min', 'Mélyszöveti masszázs 60 perc',
|
||||||
|
'Mot spenninger i nakke, skuldre og korsrygg', 'For tension in neck, shoulders and lower back', 'Nyaki, vállövi és deréktáji feszülésre',
|
||||||
|
1000, '01:00:00', @cat, 0, 0),
|
||||||
|
|
||||||
|
('massage',
|
||||||
|
'Massasje', 'Massage', 'Masszázs',
|
||||||
|
'Nakke og skuldre 30 min', 'Neck and shoulders 30 min', 'Nyak és váll 30 perc',
|
||||||
|
'Kort behandling for stillesittende arbeid', 'Short treatment for desk-bound days', 'Rövid kezelés ülőmunkához',
|
||||||
|
550, '00:30:00', @cat, 0, 0);
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------- verification
|
||||||
|
SELECT 'category' AS step, service_category_id AS id, serv_cat_slug, serv_cat_name
|
||||||
|
FROM service_categories WHERE service_category_id = @cat;
|
||||||
|
|
||||||
|
SELECT 'worker' AS step, worker_id, worker_name, service_category_id, is_active
|
||||||
|
FROM workers WHERE worker_id = @worker;
|
||||||
|
|
||||||
|
SELECT 'schedule' AS step, weekday, start_time, end_time
|
||||||
|
FROM worker_schedule WHERE worker_id = @worker ORDER BY weekday;
|
||||||
|
|
||||||
|
SELECT 'services' AS step, service_id, service_name_no, service_price, service_time, is_enabled
|
||||||
|
FROM services WHERE service_category_id = @cat ORDER BY service_id;
|
||||||
|
|
||||||
|
-- The derived-vertical check: this is what getActiveWorkers('massage') resolves.
|
||||||
|
SELECT 'derived' AS step, w.worker_id, w.worker_name,
|
||||||
|
(SELECT GROUP_CONCAT(DISTINCT s.service_type ORDER BY s.service_type)
|
||||||
|
FROM services s
|
||||||
|
WHERE s.service_category_id = w.service_category_id
|
||||||
|
AND s.is_deleted != '1') AS derived_verticals
|
||||||
|
FROM workers w WHERE w.worker_id = @worker;
|
||||||
@@ -108,13 +108,6 @@
|
|||||||
<a href="negletekniker.html" class="lesmer">Les mer</a>
|
<a href="negletekniker.html" class="lesmer">Les mer</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="position-card card-beauty">
|
|
||||||
<span class="badge">BEAUTY</span>
|
|
||||||
<h3>Massør</h3>
|
|
||||||
<p>Er du en erfaren massør? Ansettelse, leie av behandlingsrom eller provisjonsbasert samarbeid.</p>
|
|
||||||
<a href="massor.html" class="lesmer">Les mer</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,334 +0,0 @@
|
|||||||
<!DOCTYPE HTML>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
|
|
||||||
Catalyst by Pixelarity
|
|
||||||
|
|
||||||
pixelarity.com | hello@pixelarity.com
|
|
||||||
|
|
||||||
License: pixelarity.com/license
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
<html lang="no">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
|
|
||||||
<title>Studio Beve - Ledig stilling: Massør</title>
|
|
||||||
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
|
|
||||||
<link rel="icon" type="image/x-icon" href="images/favicon/favicon.ico" />
|
|
||||||
|
|
||||||
<link rel="icon" type="image/png" href="images/favicon/favicon.png" />
|
|
||||||
|
|
||||||
<link rel="icon" type="image/gif" href="images/favicon/favicon.gif" />
|
|
||||||
|
|
||||||
<!-- Opera Speed Dial Favicon -->
|
|
||||||
|
|
||||||
<link rel="icon" type="image/png" href="images/favicon/speeddial-160px.png" />
|
|
||||||
|
|
||||||
<!-- For iPhone 4 Retina display: -->
|
|
||||||
|
|
||||||
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="images/favicon/apple-touch-icon-114x114-precomposed.png">
|
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="assets/css/main.css" />
|
|
||||||
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Abril+Fatface&family=Open+Sans:ital,wght@0,700;0,800;1,700;1,800&display=swap" rel="stylesheet">
|
|
||||||
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="is-preload">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div id="page-wrapper">
|
|
||||||
|
|
||||||
<!-- Header -->
|
|
||||||
|
|
||||||
<header id="header">
|
|
||||||
|
|
||||||
<a href="https://studiobeve.no/no/beauty"><img src="images/logo.png" class="logo-kep"></a> <h1>- BEAUTY</h1>
|
|
||||||
|
|
||||||
<nav id="nav">
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
|
|
||||||
<li><a href="https://studiobeve.no/no/beauty">Forside</a></li>
|
|
||||||
|
|
||||||
<li><a href="https://studiobeve.no/no/beauty#aboutus">Om oss</a></li>
|
|
||||||
|
|
||||||
<li><a href="https://studiobeve.no/no/beauty#treatments">Behandlinger</a></li>
|
|
||||||
|
|
||||||
<li><a href="https://studiobeve.no/no/beauty#one">Priser</a></li>
|
|
||||||
|
|
||||||
<li><a href="https://studiobeve.no/no/beauty#two">Åpningstider</a></li>
|
|
||||||
|
|
||||||
<li><a href="https://studiobeve.no/no/beauty#footer">Kontakt</a></li>
|
|
||||||
|
|
||||||
<li class="booktime"><a href="https://studiobeve.no/no/booking/beauty">BESTILL TIME</a></li>
|
|
||||||
|
|
||||||
<li class="socialmedia-menu"><a href="https://www.facebook.com/bevelash/" class="icon brands fa-facebook-f"><span class="label">Facebook</span></a></li>
|
|
||||||
|
|
||||||
<li class="socialmedia-menu"><a href="https://www.instagram.com/beve_barber" class="icon brands fa-instagram"><span class="label">Instagram</span></a></li>
|
|
||||||
|
|
||||||
<li class="language"><a href="https://studiobeve.no/en/beauty/">EN</a></li>
|
|
||||||
|
|
||||||
<li class="language"><a href="https://studiobeve.no/hu/beauty/">HU</a></li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</header>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Banner -->
|
|
||||||
|
|
||||||
<section id="banner">
|
|
||||||
|
|
||||||
<img src="images/banner.jpg" style="width: 100%;" />
|
|
||||||
|
|
||||||
<!--div class="inner">
|
|
||||||
|
|
||||||
<h2>Ipsum dolore</h2>
|
|
||||||
|
|
||||||
<p>Amet lorem ipsum consequat feugiat</p>
|
|
||||||
|
|
||||||
</div-->
|
|
||||||
|
|
||||||
</section>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<section id="mobil-menu">
|
|
||||||
|
|
||||||
<div class="mobil-menucont">
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
|
|
||||||
<li class="mobil-menu-book"><a href="#">BESTILL TIME</a></li>
|
|
||||||
|
|
||||||
<li class=""><a href="https://www.facebook.com/bevelash/" class="icon brands fa-facebook-f"><span class="label">Facebook</span></a></li>
|
|
||||||
|
|
||||||
<li class=""><a href="https://www.instagram.com/beve_barber" class="icon brands fa-instagram"><span class="label">Instagram</span></a></li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- About Us -->
|
|
||||||
|
|
||||||
<section id="aboutus" class="wrapper style1">
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
|
|
||||||
<div class="inner">
|
|
||||||
|
|
||||||
<a href="./" class="back-to-list">← Alle ledige stillinger</a>
|
|
||||||
|
|
||||||
<header class="major">
|
|
||||||
|
|
||||||
<img src="images/ollo_rose.png">
|
|
||||||
|
|
||||||
<h2>Er du en erfaren massør? Bli en del av teamet hos Studio Beve!</h2>
|
|
||||||
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="bemutatkozas">
|
|
||||||
|
|
||||||
<div class="hirdetes">
|
|
||||||
<p>
|
|
||||||
<strong>Hos Studio Beve tilbyr vi flere samarbeidsformer, slik at du kan velge den løsningen som passer deg best.</strong>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Studio Beve AS er en moderne skjønnhetssalong i Trondheim, lokalisert i Innherredsveien 92, i et sentralt, lett tilgjengelig og godt besøkt område. Salongen har vært i drift i over to år og har utviklet seg jevnt siden oppstarten. Vi har en stabil og stadig voksende kundebase, et profesjonelt arbeidsmiljø, moderne lokaler, utstyr av høy kvalitet og et velfungerende online bookingsystem.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Våre tjenester inkluderer blant annet barber, hudpleie, neglebehandlinger, vippeextensions, PMU, styling av vipper og bryn, samt voksing. Vi opplever en økende etterspørsel etter profesjonell massasje fra både kvinnelige og mannlige kunder, og ønsker derfor å introdusere denne tjenesten i salongen. Derfor søker vi en erfaren og motivert massør som ønsker å bli en del av et stabilt og voksende salongmiljø på lang sikt.
|
|
||||||
</p>
|
|
||||||
<b>Samarbeidsmuligheter:</b>
|
|
||||||
<p>
|
|
||||||
Vi vet at ulike massører har forskjellige ønsker og behov. Derfor tilbyr vi tre ulike samarbeidsformer.
|
|
||||||
</p>
|
|
||||||
<b>1. Ansettelse</b>
|
|
||||||
<ul>
|
|
||||||
<li>Bruttolønn på 300 NOK per time.</li>
|
|
||||||
<li>Arbeidstid og lønnsberegning følger behandlingenes normtid.</li>
|
|
||||||
<li>Fleksibel arbeidstid tilpasset bookingene.</li>
|
|
||||||
</ul>
|
|
||||||
<b>2. Leie av behandlingsrom</b>
|
|
||||||
<ul>
|
|
||||||
<li>Samarbeid gjennom eget enkeltpersonforetak.</li>
|
|
||||||
<li>Fast månedlig leie.</li>
|
|
||||||
<li>Mulighet til å bygge opp egen kundebase.</li>
|
|
||||||
<li>Mulighet til å ta imot både egne kunder og kunder fra salongen.</li>
|
|
||||||
</ul>
|
|
||||||
<b>3. Provisjonsbasert samarbeid</b>
|
|
||||||
<ul>
|
|
||||||
<li>Samarbeid gjennom eget enkeltpersonforetak.</li>
|
|
||||||
<li>Ingen fast leiekostnad.</li>
|
|
||||||
<li>Provisjonsbasert avregning.</li>
|
|
||||||
<li>En god løsning for deg som ønsker å bygge opp kundebasen gradvis.</li>
|
|
||||||
</ul>
|
|
||||||
<p>
|
|
||||||
Samarbeidsform og økonomiske betingelser avtales individuelt ut fra erfaring, kompetanse og valgt samarbeidsmodell.
|
|
||||||
</p>
|
|
||||||
<b>Vi tilbyr:</b>
|
|
||||||
<ul>
|
|
||||||
<li>Eget, separat behandlingsrom som er dedikert til massasjebehandlinger.</li>
|
|
||||||
<li>Et hyggelig og inkluderende arbeidsmiljø i en moderne salong.</li>
|
|
||||||
<li>Moderne og stilrene lokaler.</li>
|
|
||||||
<li>Profesjonelt utstyr.</li>
|
|
||||||
<li>Ved samarbeid som selvstendig næringsdrivende tilbyr vi mulighet til å bygge opp egen kundebase, med støtte fra salongens aktive markedsføring ved behov.</li>
|
|
||||||
<li>Muligheten til å bidra aktivt i utviklingen og oppbyggingen av Studio Beves nye massasjetilbud.</li>
|
|
||||||
<li>Gode muligheter for både faglig og personlig utvikling.</li>
|
|
||||||
<li>Fleksibel arbeidstid.</li>
|
|
||||||
</ul>
|
|
||||||
<b>Personlige egenskaper:</b>
|
|
||||||
<ul>
|
|
||||||
<li>Serviceinnstilt og kundeorientert.</li>
|
|
||||||
<li>Punktlig og pålitelig.</li>
|
|
||||||
<li>Fleksibel og tilpasningsdyktig.</li>
|
|
||||||
<li>Positiv, engasjert og lidenskapelig opptatt av faget.</li>
|
|
||||||
<li>Nøyaktig og kvalitetsbevisst.</li>
|
|
||||||
</ul>
|
|
||||||
<b>Kvalifikasjoner:</b>
|
|
||||||
<ul>
|
|
||||||
<li>Utdanning som massør.</li>
|
|
||||||
<li>Erfaring med ulike massasjeteknikker.</li>
|
|
||||||
<li>Høy bevissthet rundt hygiene og kvalitet.</li>
|
|
||||||
<li>Gode kommunikasjonsevner på norsk eller engelsk.</li>
|
|
||||||
<li>Evne til å arbeide selvstendig og samtidig bidra positivt i et team.</li>
|
|
||||||
<li>Fokus på kvalitet og gode kundeopplevelser.</li>
|
|
||||||
<li>Ansvarsbevisst og profesjonell.</li>
|
|
||||||
</ul>
|
|
||||||
<b>Arbeidsoppgaver:</b>
|
|
||||||
<ul>
|
|
||||||
<li>Utføre profesjonelle massasjebehandlinger.</li>
|
|
||||||
<li>Kartlegge kundenes behov og tilpasse behandlingene individuelt.</li>
|
|
||||||
<li>Veilede kunder om behandlinger og restitusjon.</li>
|
|
||||||
<li>Sørge for god hygiene og orden på behandlingsrommet.</li>
|
|
||||||
<li>Bidra til å opprettholde Studio Beves høye faglige standard.</li>
|
|
||||||
</ul>
|
|
||||||
<p>
|
|
||||||
<b>Om Studio Beve:</b><br />
|
|
||||||
Vi er en skjønnhetssalong som tilbyr behandlinger for både kvinner og menn. Det er viktig for oss at gjestene våre får muligheten til å koble av fra hverdagens stress, hente ny energi og forlate salongen med en følelse av å ha det bedre – både fysisk og mentalt.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Kvalitetstid, personlig oppfølging, profesjonelt utstyr, høy faglig kompetanse og profesjonalitet danner grunnlaget for vår filosofi og våre tjenester.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Vi mener at skjønnhet, velvære og egenpleie ikke er knyttet til kjønn. Hos oss skal alle føle seg velkomne og finne behandlingene som passer akkurat deres behov.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<b>Tiltredelse:</b><br /> Etter avtale.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<b>Hvordan søke:</b><br />
|
|
||||||
Send oss:
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li>CV</li>
|
|
||||||
<li>En kort søknad</li>
|
|
||||||
</ul>
|
|
||||||
<p>
|
|
||||||
Søknaden sendes til: <a href="mailto:evelin@studiobeve.no">evelin@studiobeve.no</a>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Vi ber deg oppgi hvilken samarbeidsform du er interessert i når du søker.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Vi ser frem til å høre fra deg!
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<b>Kontaktperson:</b> <br />
|
|
||||||
Evelin Bence<br />
|
|
||||||
Daglig leder<br />
|
|
||||||
Studio Beve AS<br />
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Footer -->
|
|
||||||
|
|
||||||
<footer id="footer">
|
|
||||||
|
|
||||||
<div class="container footer-div">
|
|
||||||
|
|
||||||
<div class="footer-bal">
|
|
||||||
|
|
||||||
<div class="contact-block">
|
|
||||||
|
|
||||||
<!--img src="../images/logo_white.png" class="footer-logo"-->
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
|
|
||||||
<li class="companyname"><span>Studio Beve</span></li>
|
|
||||||
|
|
||||||
<li><span>Innherredsveien 92.<br> 7043 Trondheim, Norge</span></li>
|
|
||||||
|
|
||||||
<li><span>Organisasjonsnummer: 931 872 338</span></li>
|
|
||||||
|
|
||||||
<li><span><a href="mailto:info@studiobeve.no">info@studiobeve.no</a></span></li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ul class="icons">
|
|
||||||
|
|
||||||
<li><a href="https://www.facebook.com/bevelash/" class="icon brands fa-facebook-f"><span class="label">Facebook</span></a></li>
|
|
||||||
|
|
||||||
<li><a href="https://www.instagram.com/beve_barber" class="icon brands fa-instagram"><span class="label">LinkedIn</span></a></li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="footer-jobb">
|
|
||||||
|
|
||||||
<a href="https://www.google.com/maps/place/Innherredsveien+92,+7043+Trondheim,+Norway/@63.4369352,10.4350889,17z/data=!4m6!3m5!1s0x466d3199df480755:0xc8a07a1d27083152!8m2!3d63.4373339!4d10.4353781!16s%2Fg%2F11h26_1cnn?entry=ttu" target="_blank"><img src="images/map.jpg"> </a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="copyright">
|
|
||||||
|
|
||||||
© Studio Beve - Alle Rettigheter Forbeholdt
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Scripts -->
|
|
||||||
<script src="assets/js/jquery.min.js"></script>
|
|
||||||
<script src="assets/js/jquery.dropotron.min.js"></script>
|
|
||||||
<script src="assets/js/browser.min.js"></script>
|
|
||||||
<script src="assets/js/breakpoints.min.js"></script>
|
|
||||||
<script src="assets/js/util.js"></script>
|
|
||||||
<script src="assets/js/main.js"></script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -84,4 +84,39 @@
|
|||||||
</url>
|
</url>
|
||||||
|
|
||||||
|
|
||||||
|
<url>
|
||||||
|
<loc>https://studiobeve.no/no/massage</loc>
|
||||||
|
<lastmod>2026-08-10T00:00:00+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://studiobeve.no/no/massage/</loc>
|
||||||
|
<lastmod>2026-08-10T00:00:00+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://studiobeve.no/en/massage/</loc>
|
||||||
|
<lastmod>2026-08-10T00:00:00+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://studiobeve.no/hu/massage/</loc>
|
||||||
|
<lastmod>2026-08-10T00:00:00+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://studiobeve.no/no/booking/massage</loc>
|
||||||
|
<lastmod>2026-08-10T00:00:00+00:00</lastmod>
|
||||||
|
<priority>0.64</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://studiobeve.no/en/booking/massage</loc>
|
||||||
|
<lastmod>2026-08-10T00:00:00+00:00</lastmod>
|
||||||
|
<priority>0.64</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://studiobeve.no/hu/booking/massage</loc>
|
||||||
|
<lastmod>2026-08-10T00:00:00+00:00</lastmod>
|
||||||
|
<priority>0.64</priority>
|
||||||
|
</url>
|
||||||
</urlset>
|
</urlset>
|
||||||