Introduces /massage alongside barber and beauty: landing page, booking flow, admin support, home tile and SEO entries, in all three languages. Architecture - application/config/verticals.php + vertical_helper.php: one registry entry per vertical (branding, assets, views, behaviour flags). A fourth vertical is a config entry plus content files. - Strangler: barber and beauty keep pointing at their existing view files, so their rendered HTML is unchanged. Only massage uses the new generic pages/vertical-*.php and includes/vertical-*.php views, which collapse the four duplicated per-language nav/footer branches into one. - Pages::vertical() + one route; booking(), booking_finished(), _booking_error() and manage_booking() are now registry-driven. Worker/vertical coupling - getActiveWorkers() derives the vertical from services.service_category_id instead of the workers.is_barber / is_beauty flags, which were a hand-maintained cache of exactly that fact. Verified against production data: the derived set reproduced the stored flags for every worker, in both verticals. No schema change was needed for massage. - The legacy flags are now written through from the category so a rollback cannot strand a new worker, and the admin worker UI shows the derived verticals read-only instead of two dropdowns that controlled nothing. Bug fixes found along the way (all pre-existing) - booking_process() had no server-side category guard; cross-vertical mixing was prevented only by client-side JS. - add-service-form / add-worker-form emitted `selected` on every category option, so the newest category silently became the default. - update-service-form offered only barber/beauty, so editing a service of any other type silently rewrote it. - getWorkerScheduleByDay ignored schedule overrides while getAvailableTimes honoured them, so slots could be shown and then rejected. Added an override-aware getWorkerScheduleForDate() and used it in both guards. - Booking lists dereferenced a null service if one had been hard-deleted. - main.css: .tiles was tuned for exactly two tiles, including an absolutely-positioned .style1 at the 1280px breakpoint. Massage-specific behaviour, opt-in per vertical - strip_category_prefix: grouped service lists show "50 min" under the treatment heading rather than repeating the full name. The full name is carried in data-service-name so the totals panel stays unambiguous, and services.service_name is untouched for emails and admin. - single_service_booking: one treatment per booking, enforced in the UI and in booking_process(). Re-clicking the selection releases it. - Displayed treatment time (50/80/110 min) is in the service name; the booked slot (60/90/120 min) is service_time and covers changing and payment. service_time is never shown to the guest. DB migrations for dev/prod are in documents/ - additive only, no ALTER. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
294 lines
16 KiB
PHP
294 lines
16 KiB
PHP
<?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>
|