317 lines
21 KiB
XML
317 lines
21 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<odoo>
|
|
<!-- Templates inherited -->
|
|
|
|
<template id="appointments_list_layout" name="Appointment: Appointments List Layout"
|
|
inherit_id="appointment.appointments_list_layout" track="1">
|
|
<xpath expr="//t[@t-call='portal.portal_layout']" position="attributes">
|
|
<attribute name="t-call">website.layout</attribute>
|
|
</xpath>
|
|
<xpath expr="//div[hasclass('o_appointment_choice')]" position="before">
|
|
<t t-call="website_appointment.website_calendar_index"/>
|
|
</xpath>
|
|
<xpath expr="//div[hasclass('o_appointment_index')]" position="attributes">
|
|
<attribute name="class">o_appointment_index bg-o-color-4</attribute>
|
|
</xpath>
|
|
<xpath expr='//div[hasclass("o_appointment_svg")]' position="before">
|
|
<div class="alert alert-info text-center d-none" groups="appointment.group_appointment_manager">
|
|
<p class="m-0">Use the top button '<b>+ New</b>' to create an appointment type.</p>
|
|
</div>
|
|
</xpath>
|
|
</template>
|
|
|
|
<record id="appointment.appointments_list_layout" model="ir.ui.view">
|
|
<!-- As the track field is not properly overridden (the value is different whether you get it by the base class
|
|
name or the overridden name), write it to the base class as well -->
|
|
<field name="track">1</field>
|
|
</record>
|
|
|
|
<template id="appointment_info" name="Appointment: Appointment Info" inherit_id="appointment.appointment_info" track="1">
|
|
<xpath expr="//t[@t-call='portal.portal_layout']" position="attributes">
|
|
<attribute name="t-call">website.layout</attribute>
|
|
</xpath>
|
|
<xpath expr="//div[@id='wrap']" position="attributes">
|
|
<attribute name="class">o_wappointment_wrap h-100 overflow-x-hidden</attribute>
|
|
</xpath>
|
|
<xpath expr="//t[@t-set='o_portal_fullwidth_alert']" position="replace"/>
|
|
<xpath expr="//t[@t-call='appointment.staff_user_select']" position="attributes">
|
|
<attribute name="t-if">
|
|
is_manual_assign_user_resource_first and based_on_users and not skip_resource_selection
|
|
</attribute>
|
|
</xpath>
|
|
<xpath expr="//div[@name='resource_select']" position="attributes">
|
|
<attribute name="t-if">
|
|
is_manual_assign_user_resource_first and not based_on_users and not skip_resource_selection
|
|
</attribute>
|
|
</xpath>
|
|
<xpath expr="//t[@t-call='appointment.appointment_progress_bar']" position="before">
|
|
<a t-if="len(available_appointments) != 1"
|
|
class="text-truncate"
|
|
t-attf-href="/appointment?#{keep_query('filter_appointment_type_ids', 'filter_staff_user_ids', 'invite_token')}">
|
|
<i class="fa fa-long-arrow-left me-2"/>All Appointments
|
|
</a>
|
|
</xpath>
|
|
<xpath expr="//t[@t-set='selectionPossible']" position="after">
|
|
<!-- Selection is no longer possible if a selection screen was shown beforehand -->
|
|
<t t-set="selectionPossible"
|
|
t-value="selectionPossible and not (is_manual_assign_user_resource_first and appointment_type.show_avatars)"/>
|
|
</xpath>
|
|
</template>
|
|
|
|
<record id="appointment.appointment_info" model="ir.ui.view">
|
|
<!-- Write track=1 to the base class as well (see explanation above) -->
|
|
<field name="track">1</field>
|
|
</record>
|
|
|
|
<template id="appointment_progress_bar" inherit_id="appointment.appointment_progress_bar">
|
|
<xpath expr="//a[contains(@t-att-class, 'step==STEP_TIME')]" position="before">
|
|
<t t-set="is_manual_assign_user_resource_first" t-value="not appointment_type.is_auto_assign and not appointment_type.is_date_first"/>
|
|
<t t-set="STEP_OPERATOR_SELECT" t-value="10"/>
|
|
<t t-set="show_operator_select" t-value="step==STEP_OPERATOR_SELECT or is_manual_assign_user_resource_first and len(users_or_resources_possible) > 1"/>
|
|
<t t-if="show_operator_select">
|
|
<li class="d-flex align-items-center">
|
|
<a t-att-class="'text-decoration-none text-truncate ' + (step==STEP_OPERATOR_SELECT and 'fw-bold text-reset cursor-default' or step>STEP_OPERATOR_SELECT and ' ' or 'cursor-default text-muted')"
|
|
t-att-href="'#' if step<STEP_OPERATOR_SELECT or step==STEP_OPERATOR_SELECT else '/appointment/%s?%s' % (appointment_type.id, keep_query('filter_appointment_type_ids', 'filter_resource_ids', 'filter_staff_user_ids', 'invite_token'))">
|
|
<span t-if="appointment_type.schedule_based_on == 'users'">Operator</span>
|
|
<span t-else="">Meeting</span>
|
|
</a>
|
|
<span class="d-inline-block mx-sm-3 fa fa-angle-right text-muted fs-5"/>
|
|
</li>
|
|
</t>
|
|
</xpath>
|
|
</template>
|
|
|
|
<!-- Pages -->
|
|
|
|
<template id="appointment_select_operator" name="Appointment: Appointment Operators">
|
|
<t t-set="no_breadcrumbs" t-value="True"/>
|
|
<t t-call="website.layout">
|
|
<div id="wrap" class="o_wappointment_wrap h-100 overflow-x-hidden">
|
|
<div class="container-lg o_appointment o_wappointment_select_operator o_wappointment_type_options h-100" t-att-data-appointment-type-id="appointment_type.id">
|
|
<div class="row mt-4">
|
|
<div class="col-12 col-md-8">
|
|
<nav class="d-print-none d-flex justify-content-between mb-4">
|
|
<a t-if="len(available_appointments) != 1"
|
|
class="text-truncate"
|
|
t-attf-href="/appointment?#{keep_query('filter_appointment_type_ids', 'filter_staff_user_ids', 'invite_token')}">
|
|
<i class="fa fa-long-arrow-left me-2"/>All Appointments
|
|
</a>
|
|
<t t-call="appointment.appointment_progress_bar">
|
|
<t t-set="step" t-value="10"/>
|
|
</t>
|
|
</nav>
|
|
<div class="d-flex flex-wrap justify-content-between align-items-center pb-3">
|
|
<h4 class="me-2" t-if="appointment_type.schedule_based_on == 'users'">Choose who you will meet</h4>
|
|
<h4 class="me-2" t-else="">Choose what you would like to book</h4>
|
|
<a t-attf-href="/appointment/#{ appointment_type.id }?#{keep_query('*', skip_resource_selection=1)}"
|
|
class="o_wappointment_select_btn ms-auto">
|
|
<span>See all availabilities <i class="fa fa-long-arrow-right"/></span>
|
|
</a>
|
|
</div>
|
|
<div class="row">
|
|
<t t-set="showAvatars" t-value="appointment_type.show_avatars"/>
|
|
<div t-if="appointment_type.schedule_based_on == 'users'"
|
|
t-foreach="users_possible" t-as="staff_user"
|
|
class="col-md-6 col-lg-4 mb-4">
|
|
<div class="o_wappointment_card card h-100" itemscope="itemscope" itemtype="http://schema.org/Employee">
|
|
<a t-attf-href="/appointment/#{appointment_type.id}?staff_user_id=#{staff_user.id}&#{keep_query('*')}"
|
|
class="d-flex d-md-block h-100 text-reset text-decoration-none">
|
|
<header t-attf-class="o_appointment_avatar_container w-25 w-md-auto bg-secondary ratio {{'ratio-4x3' if showAvatars else 'ratio-16x9'}}">
|
|
<div t-if="showAvatars"
|
|
t-attf-style="background-image: url('/appointment/#{appointment_type.id}/avatar?user_id=#{staff_user.id}');"
|
|
class="o_appointment_avatar_background"/>
|
|
<div t-else="" class="o_appointment_avatar_background d-flex justify-content-center align-items-center">
|
|
<img class="o_appointment_avatar_background h-75 w-75 m-auto" src="/appointment/static/src/img/guy.svg"/>
|
|
</div>
|
|
</header>
|
|
<div class="card-body">
|
|
<h5 class="mb-1" t-out="staff_user.name"/>
|
|
<div class="o_wappointment_card_user_fct mb-2">
|
|
<div t-field="staff_user.partner_id.function" placeholder="Add a function here..."/>
|
|
</div>
|
|
<div class="o_wappointment_card_user_dsc text-muted small">
|
|
<div t-field="staff_user.partner_id.website_description" placeholder="Add a user description here..."/>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div t-if="appointment_type.schedule_based_on == 'resources'"
|
|
t-foreach="resources_possible" t-as="resource"
|
|
class="col-md-6 col-lg-4 mb-4">
|
|
<div class="o_wappointment_card card h-100">
|
|
<a t-attf-href="/appointment/#{appointment_type.id}?#{keep_query('*', resource_selected_id=resource.id)}"
|
|
class="d-flex d-md-block text-reset text-decoration-none h-100">
|
|
<header t-attf-class="o_appointment_avatar_container w-25 w-md-auto bg-secondary ratio {{'ratio-4x3' if showAvatars else 'ratio-16x9'}}">
|
|
<div t-if="showAvatars"
|
|
t-attf-style="background-image: url('/appointment/#{appointment_type.id}/resource_avatar?resource_id=#{resource.id}');"
|
|
class="o_appointment_avatar_background"/>
|
|
<div t-else="" class="o_appointment_avatar_background d-flex justify-content-center align-items-center">
|
|
<img class="o_appointment_avatar_background h-75 w-75 m-auto" src="/appointment/static/src/img/clock.svg"/>
|
|
</div>
|
|
</header>
|
|
<div class="card-body">
|
|
<h5 class="mb-0" t-out="resource.name"/>
|
|
<div class="o_wappointment_card_user_dsc mb-2 text-muted">
|
|
<div t-field="resource.description" placeholder="Add a resource description here..."/>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<!-- Prevent using 'resource' from the loop above as the selected one in other templates -->
|
|
<t t-set="resource" t-value="False"/>
|
|
</div>
|
|
<div class="oe_structure"/>
|
|
</div>
|
|
<t t-call="appointment.appointment_details_column"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
</template>
|
|
|
|
<template id="appointments_cards_layout" name="Appointment Types" track="1">
|
|
<t t-call="website.layout">
|
|
<div id="wrap" class="o_appointment_index">
|
|
<div class="oe_structure"/>
|
|
<t t-call="website_appointment.website_calendar_index"/>
|
|
<t t-call="website_appointment.website_calendar_index_topbar"/>
|
|
<div class="o_appointment_choice o_appointment_appointments_list">
|
|
<div class="container">
|
|
<div id="o_appointment_index_main_col" class="col-md px-0 o_wappointment_appointment_list_columns">
|
|
<div class="row row-gap-3">
|
|
<t t-call="website_appointment.appointments_cards"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="oe_structure oe_empty"/>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
</template>
|
|
|
|
|
|
<!-- Enable the customize option for the 2 layouts (cards and list)-->
|
|
<template id="website_calendar_index" name="Appointment"/>
|
|
<template id="opt_appointments_list_cards" inherit_id="website_appointment.website_calendar_index" active="True" name="Card Design"/>
|
|
|
|
<!-- Top bar -->
|
|
<template id="website_calendar_index_topbar" name="Topbar">
|
|
<div class="container">
|
|
<section class="d-flex d-print-none align-items-center justify-content-lg-end flex-wrap gap-2 mt-4 mb-3" t-if="appointment_types">
|
|
<h1 class="me-auto mb-0 h4">Choose your appointment</h1>
|
|
<div class="d-flex w-100 w-lg-25">
|
|
<t t-call="website.website_search_box_input">
|
|
<t t-set="_form_classes" t-valuef="flex-grow-1"/>
|
|
<t t-set="_classes" t-valuef="#{_classes}"/>
|
|
<t t-set="_input_classes" t-valuef="bg-light"/>
|
|
<t t-set="_submit_classes" t-valuef="btn-light"/>
|
|
<t t-set="search_type" t-valuef="appointments"/>
|
|
<t t-set="action" t-valuef="/appointment"/>
|
|
<t t-set="display_description" t-valuef="true"/>
|
|
<t t-set="display_detail" t-valuef="false"/>
|
|
<t t-set="placeholder">Search...</t>
|
|
<t t-set="search" t-value="current_search"/>
|
|
<t t-foreach="searches" t-as="search">
|
|
<input t-if="item != 'search' and item_value != 'all'" type="hidden"
|
|
t-att-name="item" t-att-value="item_value"/>
|
|
</t>
|
|
<input type="hidden" name="filter_appointment_type_ids" t-att-value="filter_appointment_type_ids"/>
|
|
<input type="hidden" name="filter_staff_user_ids" t-att-value="filter_staff_user_ids"/>
|
|
<input type="hidden" name="filter_resource_ids" t-att-value="filter_resource_ids"/>
|
|
<input type="hidden" name="invite_token" t-att-value="invite_token"/>
|
|
<t t-out="0"/>
|
|
</t>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="appointments_cards" name="Appointments Cards">
|
|
<div t-if="not appointment_types" class="col-12 o_appointment_not_found">
|
|
<div class="alert alert-info text-center d-none mt-4" groups="appointment.group_appointment_manager">
|
|
<p class="m-0">Use the top button '<b>+ New</b>' to create an appointment type.</p>
|
|
</div>
|
|
<div class="o_appointment_svg mx-auto text-center py-3 w-75">
|
|
<i class="mx-auto h3 fa fa-circle-o-notch fa-spin"/>
|
|
</div>
|
|
<div class="mt-4 text-center d-none">
|
|
<t t-if="current_search">
|
|
<h4>No result for "<t t-out="current_search"/>"</h4>
|
|
<a href="/appointment">See all appointments <i class="fa fa-long-arrow-right"/></a>
|
|
</t>
|
|
<h4 t-else="">There is currently no appointment available</h4>
|
|
</div>
|
|
</div>
|
|
<div t-foreach="appointment_types" t-as="appointment" class="col-md-6 col-lg-4 col-xl-3">
|
|
<div class="o_wappointment_card card h-100" itemscope="itemscope" itemtype="http://schema.org/Appointments">
|
|
<t t-call="website_appointment.appointment_card_top"/>
|
|
<t t-call="website_appointment.appointment_card_body"/>
|
|
</div>
|
|
</div>
|
|
<div class="d-flex justify-content-center my-3">
|
|
<t t-call="website.pager"/>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="appointment_card_top">
|
|
<div class="card-img-top position-relative">
|
|
<a t-attf-href="/appointment/#{appointment.id}?#{keep_query('filter_appointment_type_ids', 'filter_staff_user_ids', 'filter_resource_ids', 'invite_token')}"
|
|
t-attf-title="Book {{appointment.name}}">
|
|
<div t-field="appointment.image_1920" class="d-block h-100 w-100 overflow-hidden ratio ratio-16x9 object-fit-cover" t-options="{'widget': 'image', 'class': 'object-fit-cover', 'preview_image': 'image_512'}"/>
|
|
</a>
|
|
<small t-if="not appointment.website_published" class="o_appointment_unpublished badge bg-danger position-absolute top-0 end-0 mt-2 me-2" groups="base.group_user">
|
|
<i class="fa fa-ban me-2" role="presentation"/>Unpublished
|
|
</small>
|
|
<div t-if="appointment.schedule_based_on == 'users' and appointment.staff_user_ids" class="o_wappointment_card_staff_users position-absolute bottom-0 d-flex align-items-center">
|
|
<t t-if="len(appointment.staff_user_ids)" t-call="website_appointment.appointment_booking_resource_description"/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="appointment_card_body">
|
|
<div class="card-body d-flex flex-column gap-2">
|
|
<div class="d-flex align-items-start justify-content-between gap-3">
|
|
<h5 class="card-title m-0 text-break" t-field="appointment.name" itemprop="name"/>
|
|
</div>
|
|
<div class="d-flex gap-2 flex-wrap align-items-center">
|
|
<div itemprop="location" class="o_wappointment_card_location d-flex gap-1 fw-bold smaller text-muted text-break">
|
|
<t t-if="appointment.location_id">
|
|
<i class="fa fa-map-marker lh-base" role="presentation"/>
|
|
<span t-field="appointment.location_id" t-options="{'widget': 'contact', 'fields': ['name']}"/>
|
|
</t>
|
|
<t t-else="">
|
|
<i class="fa fa-video-camera lh-base" role="presentation"/>
|
|
<span class="o_not_editable">Online</span>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
<span t-if="not is_html_empty(appointment.message_intro)" class="o_wappointment_message_intro card-text text-muted overflow-hidden" t-field="appointment.message_intro" itemprop="message_intro" placeholder="Add an intro message here..."/>
|
|
<div class="mt-auto">
|
|
<a t-attf-href="/appointment/#{appointment.id}?#{keep_query('filter_appointment_type_ids', 'filter_staff_user_ids', 'filter_resource_ids', 'invite_token')}"
|
|
t-attf-title="Book {{appointment.name}}" role="button" class="btn btn-primary w-100 mt-3 o_not_editable" contenteditable="false">Book now</a>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template id='appointment_booking_resource_description' name="Avatars">
|
|
<t t-set="avatars_max_count" t-value="avatars_max_count or 6"/>
|
|
<t t-set="booking_count" t-value="len(appointment.staff_user_ids)"/>
|
|
<t t-if="appointment.show_avatars and appointment.schedule_based_on == 'users'">
|
|
<div t-att-class="booking_count == 1 and 'badge d-flex align-items-center rounded-pill py-0 ps-0 bg-light fw-normal' or ''">
|
|
<span class="o_appointment_user_avatars d-flex">
|
|
<t t-foreach="appointment.staff_user_ids[:(avatars_max_count - 1)]" t-as="staff_user">
|
|
<img t-attf-src="/appointment/#{appointment.id}/avatar?user_id=#{staff_user.id}&avatar_size=128" t-att-title="staff_user.name"
|
|
class="rounded-circle o_appointment_avatar_background o_appointment_user_avatar"/>
|
|
</t>
|
|
<span t-if="booking_count == avatars_max_count" class="o_appointment_user_avatar d-flex align-items-center justify-content-center rounded-circle bg-light"> +1 </span>
|
|
<span t-if="booking_count > avatars_max_count" class="o_appointment_user_avatar d-flex align-items-center justify-content-center rounded-circle bg-light"> +<t t-out="booking_count - (avatars_max_count - 1)"/></span>
|
|
</span>
|
|
<span t-if="booking_count == 1"><t t-out="appointment.staff_user_ids[0].name"/></span>
|
|
</div>
|
|
</t>
|
|
</template>
|
|
|
|
</odoo>
|