Feat: Home and Contact pages setup with Altcha bot protection and saving to database using alterntive layout.

This commit is contained in:
2025-07-25 19:22:17 +01:00
parent fad5336cc4
commit b76a999d01
95 changed files with 10274 additions and 2115 deletions

2
app.py
View File

@@ -27,6 +27,7 @@ from controllers.dog.dog_command_link import routes_dog_dog_command_link
from controllers.dog.home import routes_dog_home from controllers.dog.home import routes_dog_home
from controllers.dog.location import routes_dog_location from controllers.dog.location import routes_dog_location
from controllers.core.home import routes_core_home from controllers.core.home import routes_core_home
from controllers.core.contact import routes_core_contact
from controllers.legal.legal import routes_legal from controllers.legal.legal import routes_legal
from controllers.user.user import routes_user from controllers.user.user import routes_user
from extensions import db, csrf, mail, oauth from extensions import db, csrf, mail, oauth
@@ -118,6 +119,7 @@ with app.app_context():
print(f"Registered clients: {list(oauth._clients.keys())}") print(f"Registered clients: {list(oauth._clients.keys())}")
app.register_blueprint(routes_core_home) app.register_blueprint(routes_core_home)
app.register_blueprint(routes_core_contact)
app.register_blueprint(routes_dog) app.register_blueprint(routes_dog)
app.register_blueprint(routes_dog_command) app.register_blueprint(routes_dog_command)
app.register_blueprint(routes_dog_command_category) app.register_blueprint(routes_dog_command_category)

View File

View File

@@ -0,0 +1,136 @@
"""
Project: PARTS Website
Author: Edward Middleton-Smith
Precision And Research Technology Systems Limited
Technology: Business Objects
Feature: Contact_Form Business Object
"""
# internal
from business_objects.base import Base
from business_objects.db_base import SQLAlchemy_ABC
import lib.argument_validation as av
from extensions import db
from helpers.helper_app import Helper_App
# external
from dataclasses import dataclass
from typing import ClassVar
class Contact_Form(SQLAlchemy_ABC, Base):
FLAG_ALTCHA: ClassVar[str] = 'altcha'
FLAG_CONTACT_FORM: ClassVar[str] = 'contact-form'
FLAG_NAME_COMPANY: ClassVar[str] = 'name-company'
FLAG_NAME_CONTACT: ClassVar[str] = 'name-contact'
FLAG_MESSAGE: ClassVar[str] = 'message'
FLAG_RECEIVE_MARKETING_COMMUNICATIONS: ClassVar[str] = 'receive-marketing-communications'
NAME_ATTR_OPTION_VALUE: ClassVar[str] = FLAG_CONTACT_FORM
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Base.FLAG_EMAIL
__tablename__ = 'PH_Contact_Form'
__table_args__ = { 'extend_existing': True }
id_contact_form = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255))
name_contact = db.Column(db.String(255))
name_company = db.Column(db.String(255))
message = db.Column(db.Text)
receive_marketing_communications = db.Column(db.Boolean)
active = db.Column(db.Boolean)
created_on = db.Column(db.DateTime)
def __init__(self):
self.id_contact_form = 0
self.is_new = False
super().__init__()
def from_DB_Contact_Form(query_row):
_m = 'Contact_Form.from_DB_Contact_Form'
contact_form = Contact_Form()
contact_form.id_contact_form = query_row[0]
contact_form.email = query_row[1]
contact_form.name_contact = query_row[2]
contact_form.name_company = query_row[3]
contact_form.message = query_row[4]
contact_form.receive_marketing_communications = av.input_bool(query_row[5], 'receive_marketing_communications', _m)
contact_form.active = av.input_bool(query_row[6], 'active', _m)
contact_form.created_on = query_row[7]
return contact_form
@classmethod
def from_json(cls, json):
_m = 'Contact_Form.from_json'
contact_form = cls()
if json is None: return Contact_Form
Helper_App.console_log(f'{_m}\njson: {json}')
contact_form.id_contact_form = -1
contact_form.email = json[cls.FLAG_EMAIL]
contact_form.name_contact = json[cls.FLAG_NAME_CONTACT]
contact_form.name_company = json[cls.FLAG_NAME_COMPANY]
contact_form.message = json[cls.FLAG_MESSAGE]
contact_form.receive_marketing_communications = json[cls.FLAG_RECEIVE_MARKETING_COMMUNICATIONS]
contact_form.active = json[cls.FLAG_ACTIVE]
contact_form.created_on = json.get(cls.FLAG_CREATED_ON, None)
Helper_App.console_log(f'Contact_Form: {contact_form}')
return contact_form
def to_json(self):
as_json = {
self.FLAG_CONTACT_FORM: self.id_contact_form
, self.FLAG_EMAIL: self.email
, self.FLAG_NAME_CONTACT: self.name_contact
, self.FLAG_NAME_COMPANY: self.name_company
, self.FLAG_MESSAGE: self.message
, self.FLAG_RECEIVE_MARKETING_COMMUNICATIONS: self.receive_marketing_communications
, self.FLAG_ACTIVE: self.active
, self.FLAG_CREATED_ON: self.created_on
}
Helper_App.console_log(f'as_json: {as_json}')
return as_json
def __repr__(self):
return f'''
{self.__class__.__name__}(
{self.FLAG_CONTACT_FORM}: {self.id_contact_form}
{self.FLAG_EMAIL}: {self.email}
{self.FLAG_NAME_CONTACT}: {self.name_contact}
{self.FLAG_NAME_COMPANY}: {self.name_company}
{self.FLAG_MESSAGE}: {self.message}
{self.FLAG_RECEIVE_MARKETING_COMMUNICATIONS}: {self.receive_marketing_communications}
{self.FLAG_ACTIVE}: {self.active}
{self.FLAG_CREATED_ON}: {self.created_on}
)
'''
class Contact_Form_Temp(db.Model, Base):
__tablename__ = 'PH_Contact_Form_Temp'
__table_args__ = { 'extend_existing': True }
id_temp = db.Column(db.Integer, primary_key=True)
id_contact_form = db.Column(db.Integer)
email = db.Column(db.String(255))
name_contact = db.Column(db.String(255))
name_company = db.Column(db.String(255))
message = db.Column(db.Text)
receive_marketing_communications = db.Column(db.Boolean)
active = db.Column(db.Boolean)
created_on = db.Column(db.DateTime)
guid: str = db.Column(db.String(36))
def __init__(self):
super().__init__()
@classmethod
def from_contact_form(cls, contact_form):
_m = 'Contact_Form_Temp.from_Contact_Form'
temp = cls()
temp.id_contact_form = contact_form.id_contact_form
temp.email = contact_form.email
temp.name_contact = contact_form.name_contact
temp.name_company = contact_form.name_company
temp.message = contact_form.message
temp.receive_marketing_communications = contact_form.receive_marketing_communications
temp.active = contact_form.active
temp.created_on = contact_form.created_on
return temp

143
controllers/core/contact.py Normal file
View File

@@ -0,0 +1,143 @@
"""
Project: PARTS Website
Author: Edward Middleton-Smith
Precision And Research Technology Systems Limited
Technology: App Routing
Feature: Core - Contact Routes
Description:
Contact Page Controller.
"""
# IMPORTS
# internal
from business_objects.api import API
from business_objects.project_hub.contact_form import Contact_Form
from datastores.datastore_project_hub import DataStore_Project_Hub_Contact_Form
from forms.project_hub.contact import Form_Contact
from helpers.helper_app import Helper_App
from models.model_view_contact import Model_View_Contact
from models.model_view_contact_success import Model_View_Contact_Success
from models.model_view_home import Model_View_Home
import lib.argument_validation as av
# external
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, Blueprint, current_app, flash
from flask_mail import Mail, Message
from extensions import db, oauth, mail
from urllib.parse import quote_plus, urlencode
from authlib.integrations.flask_client import OAuth
from authlib.integrations.base_client import OAuthError
from urllib.parse import quote, urlparse, parse_qs
import json
import base64
import hmac
import hashlib
import datetime
from altcha import ChallengeOptions, create_challenge, verify_solution
routes_core_contact = Blueprint('routes_core_contact', __name__)
@routes_core_contact.route(Model_View_Contact.HASH_PAGE_CONTACT, methods=['GET'])
def contact():
try:
form = Form_Contact()
model = Model_View_Contact(form)
html_body = render_template('pages/core/_contact.html', model = model)
return html_body
except Exception as e:
return API.get_standard_response(
success = False,
status_code = 500,
message = f"Error: {e}",
data = None,
errors = [str(e)],
meta = None
)
@routes_core_contact.route(Model_View_Contact.HASH_GET_ALTCHA_CHALLENGE, methods=['GET'])
def create_altcha_challenge():
options = ChallengeOptions(
expires = datetime.datetime.now() + datetime.timedelta(hours=1),
max_number = 100000, # The maximum random number
hmac_key = current_app.app_config.ALTCHA_SECRET_KEY,
)
challenge = create_challenge(options)
Helper_App.console_log(f"Challenge created: {challenge}")
# return jsonify({"challenge": challenge})
return jsonify({
"algorithm": challenge.algorithm,
"challenge": challenge.challenge,
"salt": challenge.salt,
"signature": challenge.signature,
})
@routes_core_contact.route(Model_View_Contact.HASH_PAGE_CONTACT, methods=['POST'])
def contact_post():
try:
form = Form_Contact()
if form.validate_on_submit():
try:
email = form.email.data
# CC = form.CC.data # not in use
contact_name = form.contact_name.data
company_name = form.company_name.data
message = form.message.data
receive_marketing = form.receive_marketing.data
receive_marketing_text = "I would like to receive marketing emails.\n" if receive_marketing else ""
# send email
mailItem = Message("PARTS Website Contact Us Message", recipients=[current_app.config['MAIL_CONTACT_PUBLIC']])
mailItem.body = f"Dear Lord Edward Middleton-Smith,\n\n{message}\n{receive_marketing_text}\nKind regards,\n{contact_name}\n{company_name}\n{email}"
mail.send(mailItem)
# save to database
datastore = DataStore_Project_Hub_Contact_Form()
contact_form = Contact_Form.from_json(form.to_json())
datastore.save_contact_forms(
comment = contact_form.message
, contact_forms = [contact_form]
)
return redirect(url_for(Model_View_Contact.ENDPOINT_PAGE_CONTACT_SUCCESS))
except Exception as e:
return API.get_standard_response(
success = False,
status_code = 500,
message = f"Error: {e}",
data = None,
errors = [str(e)],
meta = None
)
return API.get_standard_response(
success = False,
status_code = 500,
message = f"Error: {form.errors}",
data = None,
errors = [str(form.errors)],
meta = None
)
# html_body = render_template('pages/core/_contact.html', model = model)
except Exception as e:
return API.get_standard_response(
success = False,
status_code = 500,
message = f"Error: {e}",
data = None,
errors = [str(e)],
meta = None
)
@routes_core_contact.route(Model_View_Contact.HASH_PAGE_CONTACT_SUCCESS, methods=['GET'])
def contact_success():
try:
model = Model_View_Contact_Success()
html_body = render_template('pages/core/_contact_success.html', model = model)
return html_body
except Exception as e:
return API.get_standard_response(
success = False,
status_code = 500,
message = f"Error: {e}",
data = None,
errors = [str(e)],
meta = None
)

View File

@@ -0,0 +1,113 @@
"""
Project: PARTS Website
Author: Edward Middleton-Smith
Precision And Research Technology Systems Limited
Technology: DataStores
Feature: User DataStore
Description:
Datastore for Users
"""
# internal
# from routes import bp_home
import lib.argument_validation as av
from business_objects.sql_error import SQL_Error
from business_objects.project_hub.contact_form import Contact_Form, Contact_Form_Temp
from datastores.datastore_base import DataStore_Base
from helpers.helper_app import Helper_App
from helpers.helper_db_mysql import Helper_DB_MySQL
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
from extensions import db
# external
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
db = SQLAlchemy()
class DataStore_Project_Hub_Contact_Form(DataStore_Base):
def __init__(self):
super().__init__()
@classmethod
def get_many_contact_form(cls):
_m = f'{cls.__qualname__}.get_many_contact_form'
user = cls.get_user_session()
argument_dict = {
'a_id_user': user.id_user
, 'a_debug': 0
}
Helper_App.console_log(f'argument_dict: {argument_dict}')
result = cls.db_procedure_execute('p_ph_get_many_contact_form', argument_dict)
cursor = result.cursor
# Contact_Forms
result_set_1 = cursor.fetchall()
Helper_App.console_log(f'raw contact_forms: {result_set_1}')
contact_forms = []
contact_form_indexes = {}
for row in result_set_1:
new_contact_form = Contact_Form.from_DB_contact_form(row)
contact_form_indexes[new_contact_form.id_contact_form] = len(contact_forms)
contact_forms.append(new_contact_form)
# Errors
cursor.nextset()
result_set_e = cursor.fetchall()
Helper_App.console_log(f'raw errors: {result_set_e}')
errors = []
if len(result_set_e) > 0:
errors = [SQL_Error.from_DB_record(row) for row in result_set_e]
for error in errors:
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
cls.db_cursor_clear(cursor)
return contact_forms, errors
@classmethod
def save_contact_forms(cls, comment, contact_forms):
_m = f'{cls}.save_contact_forms'
av.val_str(comment, 'comment', _m)
guid = Helper_DB_MySQL.create_guid_str()
now = datetime.now()
user = cls.get_user_session()
Helper_App.console_log(f'saving contact forms: {contact_forms}')
rows = []
for contact_form in contact_forms:
row = Contact_Form_Temp.from_contact_form(contact_form)
row.guid = guid
rows.append(row)
cls.upload_bulk(Contact_Form_Temp.__tablename__, rows, 1000)
Helper_App.console_log('Contact Forms uploaded')
argument_dict_list = {
'a_comment': comment,
'a_guid': guid,
'a_id_user': user.id_user,
'a_debug': 0
}
result = cls.db_procedure_execute('p_ph_save_contact_form', argument_dict_list)
Helper_App.console_log('Contact Forms saved')
# Errors
cursor = result.cursor
cursor.nextset()
result_set_e = cursor.fetchall()
errors = []
if len(result_set_e) > 0:
errors = [SQL_Error.from_DB_record(row) for row in result_set_e]
for error in errors:
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
cls.db_cursor_clear(cursor)
return errors

View File

View File

@@ -0,0 +1,100 @@
"""
Project: PARTS Website
Author: Edward Middleton-Smith
Precision And Research Technology Systems Limited
Technology: Backend
Feature: Contact Us Form
Description:
Defines Flask-WTF form for handling user input on Contact Us page.
"""
# IMPORTS
# internal
from business_objects.base import Base
from business_objects.project_hub.contact_form import Contact_Form
# from models.model_view_store import Model_View_Store # circular
from models.model_view_base import Model_View_Base
from forms.base import Form_Base
# external
from flask import Flask, render_template, request, flash, redirect, url_for, current_app
from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField, SubmitField, HiddenField, BooleanField, Field, EmailField
from wtforms.validators import DataRequired, Email, ValidationError
import markupsafe
from flask_wtf.recaptcha import RecaptchaField
from abc import ABCMeta, abstractmethod
import json
from altcha import verify_solution
import base64
class ALTCHAValidator:
def __init__(self, message=None):
self.message = message or 'ALTCHA verification failed'
def __call__(self, form, field):
altcha_data = field.data
if not altcha_data:
raise ValidationError(self.message)
try:
# The data is base64 encoded JSON
try:
# First try to decode it as JSON directly (if it's not base64 encoded)
altcha_payload = json.loads(altcha_data)
except json.JSONDecodeError:
# If direct JSON decoding fails, try base64 decoding first
decoded_data = base64.b64decode(altcha_data).decode('utf-8')
altcha_payload = json.loads(decoded_data)
ok, err = verify_solution(altcha_payload, current_app.app_config.ALTCHA_SECRET_KEY, check_expires=True)
if err or not ok:
raise ValidationError(self.message + ': ' + (err or 'Invalid solution'))
except Exception as e:
raise ValidationError(f'Invalid ALTCHA data: {str(e)}')
class ALTCHAField(Field):
def __init__(self, label='', validators=None, **kwargs):
validators = validators or []
validators.append(ALTCHAValidator())
super(ALTCHAField, self).__init__(label, validators, **kwargs)
def __call__(self, **kwargs):
html = f"""
<altcha-widget
challengeurl="/get-challenge"
auto="onload"
id="{self.id}"
name="{self.name}">
</altcha-widget>
"""
return markupsafe.Markup(html)
class Form_Contact(FlaskForm):
email = EmailField('Email')
contact_name = StringField('Name')
company_name = StringField('Company')
message = TextAreaField('Message')
receive_marketing = BooleanField('I would like to receive marketing emails.')
# recaptcha = RecaptchaField()
# altcha = HiddenField('ALTCHA') # , validators=[validate_altcha]
altcha = ALTCHAField('Verify you are human')
submit = SubmitField('Send Message')
def to_json(self):
return {
Base.FLAG_EMAIL: self.email.data
, Contact_Form.FLAG_NAME_CONTACT: self.contact_name.data
, Contact_Form.FLAG_NAME_COMPANY: self.company_name.data
, Contact_Form.FLAG_MESSAGE: self.message.data
, Contact_Form.FLAG_RECEIVE_MARKETING_COMMUNICATIONS: self.receive_marketing.data
, Contact_Form.FLAG_ALTCHA: self.altcha.data
, Base.FLAG_ACTIVE: True
, Base.FLAG_CREATED_ON: None
}

View File

@@ -112,6 +112,7 @@ class Model_View_Base(BaseModel, ABC):
FLAG_ASSESSMENT: ClassVar[str] = Assessment.FLAG_ASSESSMENT FLAG_ASSESSMENT: ClassVar[str] = Assessment.FLAG_ASSESSMENT
FLAG_ASSESSMENT_COMMAND_MODALITY_LINK: ClassVar[str] = Assessment_Command_Modality_Link.FLAG_ASSESSMENT_COMMAND_MODALITY_LINK FLAG_ASSESSMENT_COMMAND_MODALITY_LINK: ClassVar[str] = Assessment_Command_Modality_Link.FLAG_ASSESSMENT_COMMAND_MODALITY_LINK
FLAG_ASSESSMENT_RESPONSE: ClassVar[str] = Assessment_Response.FLAG_ASSESSMENT_RESPONSE FLAG_ASSESSMENT_RESPONSE: ClassVar[str] = Assessment_Response.FLAG_ASSESSMENT_RESPONSE
FLAG_BENEFITS: ClassVar[str] = 'benefits'
FLAG_BOOL_FALSE: ClassVar[str] = 'false' FLAG_BOOL_FALSE: ClassVar[str] = 'false'
FLAG_BOOL_TRUE: ClassVar[str] = 'true' FLAG_BOOL_TRUE: ClassVar[str] = 'true'
FLAG_BRIBE: ClassVar[str] = Bribe.FLAG_BRIBE FLAG_BRIBE: ClassVar[str] = Bribe.FLAG_BRIBE
@@ -139,6 +140,8 @@ class Model_View_Base(BaseModel, ABC):
FLAG_CONTAINER_ICON_AND_LABEL: ClassVar[str] = 'container-icon-label' FLAG_CONTAINER_ICON_AND_LABEL: ClassVar[str] = 'container-icon-label'
FLAG_CONTAINER_INPUT: ClassVar[str] = 'container-input' FLAG_CONTAINER_INPUT: ClassVar[str] = 'container-input'
FLAG_CSRF_TOKEN: ClassVar[str] = 'X-CSRFToken' FLAG_CSRF_TOKEN: ClassVar[str] = 'X-CSRFToken'
FLAG_CTA_1: ClassVar[str] = 'cta-1'
FLAG_CTA_2: ClassVar[str] = 'cta-2'
FLAG_DATA: ClassVar[str] = 'data' FLAG_DATA: ClassVar[str] = 'data'
FLAG_DATE_FROM: ClassVar[str] = Base.FLAG_DATE_FROM FLAG_DATE_FROM: ClassVar[str] = Base.FLAG_DATE_FROM
FLAG_DATE_TO: ClassVar[str] = Base.FLAG_DATE_TO FLAG_DATE_TO: ClassVar[str] = Base.FLAG_DATE_TO
@@ -159,6 +162,8 @@ class Model_View_Base(BaseModel, ABC):
FLAG_ERROR: ClassVar[str] = 'error' FLAG_ERROR: ClassVar[str] = 'error'
FLAG_EXPANDED: ClassVar[str] = 'expanded' FLAG_EXPANDED: ClassVar[str] = 'expanded'
FLAG_FAILURE: ClassVar[str] = 'failure' FLAG_FAILURE: ClassVar[str] = 'failure'
FLAG_FAQ: ClassVar[str] = 'faq'
FLAG_FEATURES: ClassVar[str] = 'features'
FLAG_FILTER: ClassVar[str] = 'filter' FLAG_FILTER: ClassVar[str] = 'filter'
FLAG_FORM: ClassVar[str] = 'form' FLAG_FORM: ClassVar[str] = 'form'
FLAG_FORM_FILTERS: ClassVar[str] = 'form-filters' FLAG_FORM_FILTERS: ClassVar[str] = 'form-filters'
@@ -272,8 +277,20 @@ class Model_View_Base(BaseModel, ABC):
NAME_COMPANY: ClassVar[str] = 'Precision And Research Technology Systems Limited - Fetch Metrics' NAME_COMPANY: ClassVar[str] = 'Precision And Research Technology Systems Limited - Fetch Metrics'
NAME_COMPANY_SHORT: ClassVar[str] = 'Fetch Metrics' NAME_COMPANY_SHORT: ClassVar[str] = 'Fetch Metrics'
NAME_CSRF_TOKEN: ClassVar[str] = 'csrf-token' NAME_CSRF_TOKEN: ClassVar[str] = 'csrf-token'
URL_GITHUB: ClassVar[str] = 'https://github.com/Teddy-1024' USERNAME_DISCORD: ClassVar[str] = 'Fetch Metrics'
URL_LINKEDIN: ClassVar[str] = 'https://uk.linkedin.com/in/teddyms' USERNAME_GITHUB: ClassVar[str] = 'Teddy-1024'
USERNAME_INSTAGRAM: ClassVar[str] = 'fetchmetrics'
USERNAME_LINKEDIN: ClassVar[str] = 'teddyms'
USERNAME_REDDIT: ClassVar[str] = 'Fetch-Metrics'
USERNAME_TIKTOK: ClassVar[str] = 'fetchmetrics'
USERNAME_TWITTER: ClassVar[str] = 'FetchMetrics'
URL_DISCORD: ClassVar[str] = f'https://discord.gg/WFZN6WuZ'
URL_GITHUB: ClassVar[str] = f'https://github.com/{USERNAME_GITHUB}'
URL_INSTAGRAM: ClassVar[str] = f'https://www.instagram.com/{USERNAME_INSTAGRAM}/'
URL_LINKEDIN: ClassVar[str] = f'https://uk.linkedin.com/in/{USERNAME_LINKEDIN}'
URL_REDDIT: ClassVar[str] = f'https://www.reddit.com/u/{USERNAME_REDDIT}/s/gZKEz2ZwHN'
URL_TIKTOK: ClassVar[str] = f'https://www.tiktok.com/@{USERNAME_TIKTOK}'
URL_TWITTER: ClassVar[str] = f'https://x.com/{USERNAME_TWITTER}'
_title: str _title: str
hash_page_current: str hash_page_current: str

View File

@@ -0,0 +1,31 @@
"""
Project: PARTS Website
Author: Edward Middleton-Smith
Precision And Research Technology Systems Limited
Technology: View Models
Feature: Contact View Model
Description:
Data model for contact view
"""
# internal
from business_objects.project_hub.contact_form import Contact_Form
from models.model_view_base import Model_View_Base
# from routes import bp_home
from lib import argument_validation as av
from forms.project_hub.contact import Form_Contact
# external
from flask_wtf import FlaskForm
from abc import abstractproperty
from pydantic import BaseModel
from typing import ClassVar
class Model_View_Contact(Model_View_Base):
form_contact: Form_Contact
def __init__(self, form_contact, hash_page_current=Model_View_Base.HASH_PAGE_CONTACT, **kwargs):
super().__init__(hash_page_current=hash_page_current, form_contact=form_contact, **kwargs)
self._title = 'Contact'

View File

@@ -0,0 +1,28 @@
"""
Project: PARTS Website
Author: Edward Middleton-Smith
Precision And Research Technology Systems Limited
Technology: View Models
Feature: Contact View Model
Description:
Data model for contact view
"""
# internal
from models.model_view_base import Model_View_Base
# from routes import bp_home
from lib import argument_validation as av
# from forms.contact import Form_Contact
# external
from flask_wtf import FlaskForm
from abc import abstractproperty
from pydantic import BaseModel
from typing import ClassVar
class Model_View_Contact_Success(Model_View_Base):
def __init__(self, hash_page_current=Model_View_Base.HASH_PAGE_CONTACT_SUCCESS, **kwargs):
super().__init__(hash_page_current=hash_page_current, **kwargs)
self._title = 'Contact Success'

View File

@@ -14,8 +14,15 @@ Data model for home view
from models.model_view_base import Model_View_Base from models.model_view_base import Model_View_Base
# from routes import bp_home # from routes import bp_home
# external # external
from typing import ClassVar
class Model_View_Home(Model_View_Base): class Model_View_Home(Model_View_Base):
FLAG_EARLY_ACCESS: ClassVar[str] = 'early-access'
FLAG_PROBLEM: ClassVar[str] = 'problem'
FLAG_SOCIAL_PROOF: ClassVar[str] = 'social-proof'
FLAG_SOLUTION: ClassVar[str] = 'solution'
def __init__(self, hash_page_current=Model_View_Base.HASH_PAGE_HOME): def __init__(self, hash_page_current=Model_View_Base.HASH_PAGE_HOME):
super().__init__(hash_page_current=hash_page_current) super().__init__(hash_page_current=hash_page_current)
self._title = 'Home' self._title = 'Home'

View File

@@ -1,32 +1,26 @@
USE demo; USE demo;
DROP PROCEDURE IF EXISTS demo.p_dog_get_many_response_quality_metric; DROP PROCEDURE IF EXISTS demo.p_ph_save_contact_form;
DELIMITER // DELIMITER //
CREATE PROCEDURE demo.p_dog_get_many_response_quality_metric ( CREATE PROCEDURE demo.p_ph_save_contact_form (
IN a_id_user INT IN a_comment VARCHAR(500),
, IN a_get_all_response_quality_metric BIT IN a_guid BINARY(36),
, IN a_get_inactive_response_quality_metric BIT IN a_id_user INT,
, IN a_ids_response_quality_metric TEXT IN a_debug BIT
, IN a_names_response_quality_metric TEXT
, IN a_require_all_id_search_filters_met BIT
, IN a_require_any_id_search_filters_met BIT
, IN a_require_all_non_id_search_filters_met BIT
, IN a_require_any_non_id_search_filters_met BIT
, IN a_debug BIT
) )
BEGIN BEGIN
DECLARE v_can_view BIT; DECLARE v_code_type_error_bad_data VARCHAR(100);
DECLARE v_code_type_error_bad_data VARCHAR(100);
DECLARE v_code_type_error_no_permission VARCHAR(100);
DECLARE v_guid BINARY(36);
DECLARE v_id_access_level_view INT; DECLARE v_id_access_level_view INT;
DECLARE v_id_minimum INT; DECLARE v_id_access_level_edit INT;
DECLARE v_id_permission_dog_view INT; DECLARE v_id_change_set INT;
DECLARE v_id_permission_contact_form_admin INT;
DECLARE v_id_permission_contact_form_new INT;
DECLARE v_id_type_error_bad_data INT; DECLARE v_id_type_error_bad_data INT;
DECLARE v_id_type_error_no_permission INT;
DECLARE v_time_start TIMESTAMP(6); DECLARE v_time_start TIMESTAMP(6);
DECLARE v_can_admin BIT;
DECLARE v_can_create BIT;
DECLARE exit handler for SQLEXCEPTION DECLARE exit handler for SQLEXCEPTION
BEGIN BEGIN
@@ -39,10 +33,10 @@ BEGIN
ROLLBACK; ROLLBACK;
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_Msg_Error ( CREATE TEMPORARY TABLE IF NOT EXISTS tmp_Msg_Error (
id_error INT NOT NULL PRIMARY KEY AUTO_INCREMENT display_order INT NOT NULL PRIMARY KEY AUTO_INCREMENT
, id_type INT NULL , id_type INT NULL
, code VARCHAR(250) NOT NULL , code VARCHAR(50) NOT NULL
, msg TEXT NOT NULL , msg VARCHAR(4000) NOT NULL
); );
INSERT INTO tmp_Msg_Error ( INSERT INTO tmp_Msg_Error (
@@ -58,94 +52,138 @@ BEGIN
WHERE MET.code = 'MYSQL_ERROR' WHERE MET.code = 'MYSQL_ERROR'
; ;
SELECT SELECT *
t_ERROR.id_error FROM tmp_Msg_Error;
, t_ERROR.id_type DROP TABLE IF EXISTS tmp_Msg_Error
, t_ERROR.code
, ERROR_TYPE.name
, ERROR_TYPE.description
, ERROR_TYPE.is_breaking_error
, ERROR_TYPE.background_colour
, ERROR_TYPE.text_colour
, t_ERROR.msg
FROM tmp_Msg_Error t_ERROR
INNER JOIN demo.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type
; ;
DROP TABLE IF EXISTS tmp_Msg_Error;
END; END;
SET v_time_start := CURRENT_TIMESTAMP(6); SET v_time_start := CURRENT_TIMESTAMP(6);
SET v_guid := UUID();
SET v_code_type_error_bad_data := 'BAD_DATA'; SET v_code_type_error_bad_data := 'BAD_DATA';
SET v_code_type_error_no_permission := 'NO_PERMISSION'; SET v_id_type_error_bad_data := (SELECT id_type FROM demo.CORE_Msg_Error_Type WHERE code = v_code_type_error_bad_data LIMIT 1);
SET v_id_type_error_bad_data := (SELECT ERROR_TYPE.id_type FROM demo.CORE_Msg_Error_Type ERROR_TYPE WHERE ERROR_TYPE.code = v_code_type_error_bad_data LIMIT 1); SET v_id_permission_contact_form_admin := (SELECT id_permission FROM demo.DOG_Permission P WHERE P.code = 'CONTACT_FORM_ADMIN' LIMIT 1);
SET v_id_type_error_no_permission := (SELECT ERROR_TYPE.id_type FROM demo.CORE_Msg_Error_Type ERROR_TYPE WHERE ERROR_TYPE.code = v_code_type_error_no_permission LIMIT 1); SET v_id_permission_contact_form_new := (SELECT id_permission FROM demo.DOG_Permission P WHERE P.code = 'CONTACT_FORM_CREATE' LIMIT 1);
SET v_id_permission_dog_view := (SELECT PERMISSION.id_permission FROM demo.DOG_Permission PERMISSION WHERE PERMISSION.code = 'DOG_VIEW' LIMIT 1);
SET v_id_access_level_view := (SELECT ACCESS_LEVEL.id_access_level FROM demo.DOG_Access_Level ACCESS_LEVEL WHERE ACCESS_LEVEL.code = 'VIEW' LIMIT 1);
SET a_id_user := IFNULL(a_id_user, 0); CALL demo.p_core_validate_guid ( a_guid );
/*
SET a_get_all_response_quality_metric := IFNULL(a_get_all_response_quality_metric, 0);
SET a_get_inactive_response_quality_metric := IFNULL(a_get_inactive_response_quality_metric, 0);
SET a_ids_response_quality_metric := TRIM(IFNULL(a_ids_response_quality_metric, ''));
SET a_names_response_quality_metric := TRIM(IFNULL(a_names_response_quality_metric, ''));
SET a_require_all_id_search_filters_met := IFNULL(a_require_all_id_search_filters_met, 1);
SET a_require_any_id_search_filters_met := IFNULL(a_require_any_id_search_filters_met, 1);
SET a_require_all_non_id_search_filters_met := IFNULL(a_require_all_non_id_search_filters_met, 0);
SET a_require_any_non_id_search_filters_met := IFNULL(a_require_any_non_id_search_filters_met, 1);
*/
SET a_debug := IFNULL(a_debug, 0);
IF a_debug = 1 THEN DROP TABLE IF EXISTS tmp_Contact_Form;
SELECT
a_id_user
, a_get_all_response_quality_metric
, a_get_inactive_response_quality_metric
, a_ids_response_quality_metric
, a_names_response_quality_metric
, a_require_all_id_search_filters_met
, a_require_any_id_search_filters_met
, a_require_all_non_id_search_filters_met
, a_require_any_non_id_search_filters_met
, a_debug
;
SELECT
v_id_type_error_bad_data
, v_id_type_error_no_permission
, v_guid
, v_id_permission_dog_view
, v_time_start
;
END IF;
DROP TEMPORARY TABLE IF EXISTS tmp_Msg_Error;
DROP TEMPORARY TABLE IF EXISTS tmp_Response_Quality_Metric;
CREATE TEMPORARY TABLE tmp_Response_Quality_Metric ( CREATE TEMPORARY TABLE tmp_Contact_Form (
id_metric INT NOT NULL id_contact_form INT NOT NULL
, id_unit_measurement INT , email VARCHAR(255) NOT NULL
, code VARCHAR(250) , name_contact VARCHAR(255) NOT NULL
, name VARCHAR(250) , name_company VARCHAR(255) NOT NULL
, value_min DOUBLE , message TEXT NOT NULL
, value_max DOUBLE , receive_marketing_communications BIT NOT NULL
, active BIT , active BIT NOT NULL
, does_meet_id_filters BIT NOT NULL , name_error VARCHAR(255)
, does_meet_non_id_filters BIT NOT NULL , is_new BIT NOT NULL
); );
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_Msg_Error ( CREATE TEMPORARY TABLE IF NOT EXISTS tmp_Msg_Error (
id_error INT NOT NULL PRIMARY KEY AUTO_INCREMENT display_order INT NOT NULL PRIMARY KEY AUTO_INCREMENT
, id_type INT NULL , id_type INT NULL
, code VARCHAR(250) NOT NULL , code VARCHAR(50) NOT NULL
, msg TEXT NOT NULL , msg VARCHAR(4000) NOT NULL
); );
-- Get data from Temp table
INSERT INTO tmp_Contact_Form (
id_contact_form
, email
, name_contact
, name_company
, message
, receive_marketing_communications
, active
, is_new
)
SELECT
CF_T.id_contact_form AS id_contact_form
, IFNULL(CF_T.email, CF.email) AS code
, IFNULL(CF_T.name_contact, CF.name_contact) AS name_contact
, IFNULL(CF_T.name_company, CF.name_company) AS name_company
, IFNULL(CF_T.message, CF.message) AS message
, COALESCE(CF_T.receive_marketing_communications, CF.receive_marketing_communications, 0) AS receive_marketing_communications
, COALESCE(CF_T.active, CF.active, 1) AS active
, CASE WHEN IFNULL(CF_T.id_contact_form, 0) < 1 THEN 1 ELSE 0 END AS is_new
FROM demo.PH_Contact_Form_Temp CF_T
LEFT JOIN demo.PH_Contact_Form CF ON CF_T.id_contact_form = CF.id_contact_form
WHERE CF_T.guid = a_guid
;
UPDATE tmp_Contact_Form t_CF
SET name_error = COALESCE(t_CF.email, t_CF.name_company, t_CF.name_contact, t_CF.message, '(No Contact Form)')
;
-- Validation
-- Missing mandatory fields
-- email
IF EXISTS (SELECT * FROM tmp_Contact_Form t_CF WHERE ISNULL(t_CF.email) LIMIT 1) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Contact Form(s) do not have an Email: ', GROUP_CONCAT(t_CF.name_error SEPARATOR ', ')) AS msg
FROM tmp_Contact_Form t_CF
WHERE ISNULL(t_CF.email)
;
END IF;
-- name_contact
IF EXISTS (SELECT * FROM tmp_Contact_Form t_CF WHERE ISNULL(t_CF.name_contact) LIMIT 1) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Contact Form(s) do not have a Contact Name: ', GROUP_CONCAT(t_CF.name_error SEPARATOR ', ')) AS msg
FROM tmp_Contact_Form t_CF
WHERE ISNULL(t_CF.name_contact)
;
END IF;
-- name_company
IF EXISTS (SELECT * FROM tmp_Contact_Form t_CF WHERE ISNULL(t_CF.name_company) LIMIT 1) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Contact Form(s) do not have a Company Name: ', GROUP_CONCAT(t_CF.name_error SEPARATOR ', ')) AS msg
FROM tmp_Contact_Form t_CF
WHERE ISNULL(t_CF.name)
;
END IF;
-- message
IF EXISTS (SELECT * FROM tmp_Contact_Form t_CF WHERE ISNULL(t_CF.message) LIMIT 1) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Contact Form(s) do not have a Message: ', GROUP_CONCAT(t_CF.name_error SEPARATOR ', ')) AS msg
FROM tmp_Contact_Form t_CF
WHERE ISNULL(t_CF.message)
;
END IF;
-- Permissions -- Permissions
IF a_debug = 1 THEN IF a_debug = 1 THEN
SELECT SELECT
v_guid a_guid
, 0 -- get_all_user , 0 -- get_all_user
, 0 -- get_inactive_user , 0 -- get_inactive_user
, a_id_user -- ids_user , a_id_user -- ids_user
@@ -156,7 +194,7 @@ BEGIN
, 1 -- a_require_any_id_search_filters_met , 1 -- a_require_any_id_search_filters_met
, 0 -- a_require_all_non_id_search_filters_met , 0 -- a_require_all_non_id_search_filters_met
, 0 -- a_require_any_non_id_search_filters_met , 0 -- a_require_any_non_id_search_filters_met
, v_id_permission_dog_view -- ids_permission , v_id_permission_contact_form_admin -- ids_permission
, v_id_access_level_view -- ids_access_level , v_id_access_level_view -- ids_access_level
, 0 -- a_show_errors , 0 -- a_show_errors
, 0 -- a_debug , 0 -- a_debug
@@ -164,7 +202,7 @@ BEGIN
END IF; END IF;
CALL demo.p_dog_calc_user( CALL demo.p_dog_calc_user(
v_guid a_guid
, 0 -- get_all_user , 0 -- get_all_user
, 0 -- get_inactive_user , 0 -- get_inactive_user
, a_id_user -- ids_user , a_id_user -- ids_user
@@ -175,7 +213,7 @@ BEGIN
, 1 -- a_require_any_id_search_filters_met , 1 -- a_require_any_id_search_filters_met
, 0 -- a_require_all_non_id_search_filters_met , 0 -- a_require_all_non_id_search_filters_met
, 0 -- a_require_any_non_id_search_filters_met , 0 -- a_require_any_non_id_search_filters_met
, v_id_permission_dog_view -- ids_permission , v_id_permission_contact_form_admin -- ids_permission
, v_id_access_level_view -- ids_access_level , v_id_access_level_view -- ids_access_level
, 0 -- a_show_errors , 0 -- a_show_errors
, 0 -- a_debug , 0 -- a_debug
@@ -184,19 +222,83 @@ BEGIN
SELECT SELECT
IFNULL(CALC_USER_T.has_access, 0) IFNULL(CALC_USER_T.has_access, 0)
INTO INTO
v_can_view v_can_admin
FROM demo.DOG_Calc_User_Temp CALC_USER_T FROM demo.DOG_Calc_User_Temp CALC_USER_T
WHERE CALC_USER_T.GUID = v_guid WHERE CALC_USER_T.GUID = a_guid
LIMIT 1 LIMIT 1
; ;
IF a_debug = 1 THEN IF a_debug = 1 THEN
SELECT v_can_view; SELECT v_can_admin;
SELECT COUNT(*) AS Count_Errors FROM tmp_Msg_Error t_ERROR; SELECT COUNT(*) AS Count_Errors FROM tmp_Msg_Error t_ERROR;
SELECT * FROM tmp_Msg_Error t_ERROR; SELECT * FROM tmp_Msg_Error t_ERROR;
END IF; END IF;
CALL demo.p_dog_clear_calc_user(
a_guid
, 0 -- a_debug
);
IF a_debug = 1 THEN
SELECT
a_guid
, 0 -- get_all_user
, 0 -- get_inactive_user
, a_id_user -- ids_user
, '' -- a_auth0_ids_user
, '' -- a_names_user
, '' -- a_emails_user
, 1 -- a_require_all_id_search_filters_met
, 1 -- a_require_any_id_search_filters_met
, 0 -- a_require_all_non_id_search_filters_met
, 0 -- a_require_any_non_id_search_filters_met
, v_id_permission_contact_form_new -- ids_permission
, v_id_access_level_view -- ids_access_level
, 0 -- a_show_errors
, 0 -- a_debug
;
END IF;
IF (v_can_view = 0) THEN CALL demo.p_dog_calc_user(
a_guid
, 0 -- get_all_user
, 0 -- get_inactive_user
, a_id_user -- ids_user
, '' -- a_auth0_ids_user
, '' -- a_names_user
, '' -- a_emails_user
, 1 -- a_require_all_id_search_filters_met
, 1 -- a_require_any_id_search_filters_met
, 0 -- a_require_all_non_id_search_filters_met
, 0 -- a_require_any_non_id_search_filters_met
, v_id_permission_contact_form_new -- ids_permission
, v_id_access_level_view -- ids_access_level
, 0 -- a_show_errors
, 0 -- a_debug
);
SELECT
IFNULL(CALC_USER_T.has_access, 0)
INTO
v_can_create
FROM demo.DOG_Calc_User_Temp CALC_USER_T
WHERE CALC_USER_T.GUID = a_guid
LIMIT 1
;
IF a_debug = 1 THEN
SELECT v_can_create;
SELECT COUNT(*) AS Count_Errors FROM tmp_Msg_Error t_ERROR;
SELECT * FROM tmp_Msg_Error t_ERROR;
END IF;
CALL demo.p_dog_clear_calc_user(
a_guid
, 0 -- a_debug
);
IF (v_can_admin = 0 AND EXISTS(SELECT * FROM tmp_Contact_Form WHERE is_new = 0)) THEN
DELETE t_ME DELETE t_ME
FROM tmp_Msg_Error t_ME FROM tmp_Msg_Error t_ME
WHERE t_ME.id_type <> v_id_type_error_no_permission WHERE t_ME.id_type <> v_id_type_error_no_permission
@@ -204,186 +306,131 @@ BEGIN
INSERT INTO tmp_Msg_Error ( INSERT INTO tmp_Msg_Error (
id_type id_type
, code , code
, msg , msg
) )
VALUES ( VALUES (
v_id_type_error_no_permission v_id_type_error_no_permission
, v_code_type_error_no_permission , v_code_type_error_no_permission
, 'You do not have permission to view RESPONSE_QUALITY_METRIC.' , 'You do not have permission to admin Contact Forms.'
) )
; ;
END IF; END IF;
IF EXISTS (SELECT * FROM tmp_Msg_Error LIMIT 1) THEN
IF a_debug = 1 THEN
SELECT * from tmp_Contact_Form;
END IF;
DELETE FROM tmp_Contact_Form;
END IF;
IF NOT EXISTS (SELECT * FROM tmp_Msg_Error LIMIT 1) THEN
START TRANSACTION;
INSERT INTO demo.PH_Contact_Form_Change_Set (
comment
, id_user_updated_last_by
, updated_last_on
)
VALUES (
a_comment
, a_id_user
, v_time_start
)
;
SET v_id_change_set := LAST_INSERT_ID();
UPDATE demo.PH_Contact_Form CF
INNER JOIN tmp_Contact_Form t_CF
ON CF.id_contact_form = t_CF.id_contact_form
AND t_CF.is_new = 0
SET
CF.email = t_CF.email
, CF.name_contact = t_CF.name_contact
, CF.name_company = t_CF.name_company
, CF.message = t_CF.message
, CF.receive_marketing_communications = t_CF.receive_marketing_communications
, CF.active = t_CF.active
, CF.id_change_set = v_id_change_set
;
INSERT INTO demo.PH_Contact_Form (
email
, name_contact
, name_company
, message
, receive_marketing_communications
, active
, id_user_created_by
, created_on
)
SELECT
t_CF.email AS email
, t_CF.name_contact AS name_contact
, t_CF.name_company AS name_company
, t_CF.message AS message
, t_CF.receive_marketing_communications AS receive_marketing_communications
, t_CF.active AS active
, a_id_user AS created_by
, v_time_start AS created_on
FROM tmp_Contact_Form t_CF
WHERE
t_CF.is_new = 1
AND t_CF.active = 1
;
COMMIT;
END IF;
CALL demo.p_dog_clear_calc_user( START TRANSACTION;
v_guid
, 0 -- a_debug
);
DELETE FROM demo.PH_Contact_Form_Temp
-- Call Response_Quality_Metric Calc WHERE GUID = a_guid
IF NOT EXISTS(SELECT * FROM tmp_Msg_Error t_ERROR INNER JOIN demo.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type WHERE ERROR_TYPE.is_breaking_error = 1 LIMIT 1) THEN
IF a_debug = 1 THEN
SELECT
v_guid -- a_guid
, a_id_user -- a_id_user
, a_get_all_response_quality_metric -- a_get_all_response_quality_metric
, a_get_inactive_response_quality_metric -- a_get_inactive_response_quality_metric
, a_ids_response_quality_metric -- a_ids_response_quality_metric
, a_names_response_quality_metric -- a_names_response_quality_metric
, a_require_all_id_search_filters_met -- a_require_all_id_search_filters_met
, a_require_any_id_search_filters_met -- a_require_any_id_search_filters_met
, a_require_all_non_id_search_filters_met -- a_require_all_non_id_search_filters_met
, a_require_any_non_id_search_filters_met -- a_require_any_non_id_search_filters_met
, 0 -- a_show_errors
, 0 -- a_debug
;
END IF;
CALL demo.p_dog_calc_response_quality_metric (
v_guid -- a_guid
, a_id_user -- a_id_user
, a_get_all_response_quality_metric -- a_get_all_response_quality_metric
, a_get_inactive_response_quality_metric -- a_get_inactive_response_quality_metric
, a_ids_response_quality_metric -- a_ids_response_quality_metric
, a_names_response_quality_metric -- a_names_response_quality_metric
, a_require_all_id_search_filters_met -- a_require_all_id_search_filters_met
, a_require_any_id_search_filters_met -- a_require_any_id_search_filters_met
, a_require_all_non_id_search_filters_met -- a_require_all_non_id_search_filters_met
, a_require_any_non_id_search_filters_met -- a_require_any_non_id_search_filters_met
, 0 -- a_show_errors
, 0 -- a_debug
);
IF a_debug = 1 THEN
SELECT COUNT(*) FROM demo.DOG_Response_Quality_Metric_Temp;
SELECT * FROM demo.DOG_Response_Quality_Metric_Temp;
END IF;
INSERT INTO tmp_Response_Quality_Metric (
id_metric
, id_unit_measurement
, code
, name
, value_min
, value_max
, active
, does_meet_id_filters
, does_meet_non_id_filters
)
SELECT
RESPONSE_QUALITY_METRIC_T.id_metric
, RESPONSE_QUALITY_METRIC_T.id_unit_measurement
, RESPONSE_QUALITY_METRIC_T.code
, RESPONSE_QUALITY_METRIC_T.name
, RESPONSE_QUALITY_METRIC_T.value_min
, RESPONSE_QUALITY_METRIC_T.value_max
, RESPONSE_QUALITY_METRIC_T.active
, RESPONSE_QUALITY_METRIC_T.does_meet_id_filters
, RESPONSE_QUALITY_METRIC_T.does_meet_non_id_filters
FROM demo.DOG_Response_Quality_Metric_Temp RESPONSE_QUALITY_METRIC_T
WHERE RESPONSE_QUALITY_METRIC_T.GUID = v_guid
; ;
IF a_debug = 1 THEN COMMIT;
SELECT COUNT(*) FROM tmp_Response_Quality_Metric;
SELECT * FROM tmp_Response_Quality_Metric;
END IF;
END IF;
-- Filter outputs
IF EXISTS(SELECT * FROM tmp_Msg_Error t_ERROR INNER JOIN demo.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type WHERE ERROR_TYPE.is_breaking_error = 1 LIMIT 1) THEN
IF a_debug = 1 THEN
SELECT * FROM tmp_Response_Quality_Metric;
END IF;
DELETE FROM tmp_Response_Quality_Metric;
END IF;
-- Outputs
-- RESPONSE_QUALITY_METRIC
SELECT
t_RESPONSE_QUALITY_METRIC.id_metric
, t_RESPONSE_QUALITY_METRIC.id_unit_measurement
, UNIT_MEASUREMENT.name_singular AS name_singular_unit_measurement
, UNIT_MEASUREMENT.name_plural AS name_plural_unit_measurement
, UNIT_MEASUREMENT.symbol AS symbol_unit_measurement
, t_RESPONSE_QUALITY_METRIC.code
, t_RESPONSE_QUALITY_METRIC.name
, t_RESPONSE_QUALITY_METRIC.value_min
, t_RESPONSE_QUALITY_METRIC.value_max
, t_RESPONSE_QUALITY_METRIC.active
, t_RESPONSE_QUALITY_METRIC.does_meet_id_filters
, t_RESPONSE_QUALITY_METRIC.does_meet_non_id_filters
FROM tmp_Response_Quality_Metric t_RESPONSE_QUALITY_METRIC
LEFT JOIN demo.DOG_Response_Quality_Metric RESPONSE_QUALITY_METRIC ON t_RESPONSE_QUALITY_METRIC.id_metric = RESPONSE_QUALITY_METRIC.id_metric
LEFT JOIN demo.DOG_Unit_Measurement UNIT_MEASUREMENT ON t_RESPONSE_QUALITY_METRIC.id_unit_measurement = UNIT_MEASUREMENT.id_unit_measurement
ORDER BY t_RESPONSE_QUALITY_METRIC.name
;
-- Errors -- Errors
SELECT SELECT *
t_ERROR.id_error FROM tmp_Msg_Error t_ME
, t_ERROR.id_type INNER JOIN demo.CORE_Msg_Error_Type MET ON t_ME.id_type = MET.id_type
, t_ERROR.code
, ERROR_TYPE.name
, ERROR_TYPE.description
, ERROR_TYPE.is_breaking_error
, ERROR_TYPE.background_colour
, ERROR_TYPE.text_colour
, t_ERROR.msg
FROM tmp_Msg_Error t_ERROR
INNER JOIN demo.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type
; ;
IF a_debug = 1 AND v_can_view = 1 THEN IF a_debug = 1 THEN
SELECT * FROM tmp_Response_Quality_Metric; SELECT * from tmp_Contact_Form;
END IF; END IF;
CALL demo.p_dog_clear_calc_response_quality_metric( DROP TEMPORARY TABLE tmp_Contact_Form;
v_guid -- a_guid DROP TEMPORARY TABLE tmp_Msg_Error;
, 0 -- a_debug
);
DROP TEMPORARY TABLE IF EXISTS tmp_Msg_Error; IF a_debug = 1 THEN
DROP TEMPORARY TABLE IF EXISTS tmp_Response_Quality_Metric;
IF a_debug = 1 THEN
CALL demo.p_core_debug_timing_reporting ( v_time_start ); CALL demo.p_core_debug_timing_reporting ( v_time_start );
END IF; END IF;
END // END //
DELIMITER ; DELIMITER ;
/* select
*
-- COUNT(*)
-- delete
from demo.PH_Contact_Form_Temp
;
CALL demo.p_dog_get_many_response_quality_metric (
1 -- 'auth0|6582b95c895d09a70ba10fef', -- a_id_user CALL demo.p_ph_save_contact_form (
, 1 -- a_get_all_response_quality_metric 'nipples'
, 0 -- a_get_inactive_response_quality_metric , (SELECT GUID FROM demo.PH_Contact_Form_Temp ORDER BY id_temp DESC LIMIT 1)
, '' -- a_ids_response_quality_metric , 1
, '' -- a_names_response_quality_metric , 1
, 1 -- a_require_all_id_search_filters_met
, 1 -- a_require_any_id_search_filters_met
, 0 -- a_require_all_non_id_search_filters_met
, 1 -- a_require_any_non_id_search_filters_met
, 1 -- a_debug
); );
select
*
-- COUNT(*)
-- delete
from demo.PH_Contact_Form_Temp
;
CALL demo.p_dog_get_many_response_quality_metric (
1 -- 'auth0|6582b95c895d09a70ba10fef', -- a_id_user
, 1 -- a_get_all_response_quality_metric
, 0 -- a_get_inactive_response_quality_metric
, '' -- a_ids_response_quality_metric
, 'pat,point' -- a_names_response_quality_metric
, 1 -- a_require_all_id_search_filters_met
, 1 -- a_require_any_id_search_filters_met
, 0 -- a_require_all_non_id_search_filters_met
, 1 -- a_require_any_non_id_search_filters_met
, 1 -- a_debug
);
*/

View File

@@ -14,6 +14,12 @@ DROP TABLE IF EXISTS parts.tmp_dog_User_Role_Link;
-- Permanent Tables -- Permanent Tables
DROP TABLE IF EXISTS parts.PH_Contact_Form_Temp;
DROP TABLE IF EXISTS parts.PH_Contact_Form_Audit;
DROP TABLE IF EXISTS parts.PH_Contact_Form;
DROP TABLE IF EXISTS parts.PH_Contact_Form_Change_Set;
DROP TABLE IF EXISTS parts.DOG_Assessment_Response_Temp; DROP TABLE IF EXISTS parts.DOG_Assessment_Response_Temp;
DROP TABLE IF EXISTS parts.DOG_Assessment_Response_Audit; DROP TABLE IF EXISTS parts.DOG_Assessment_Response_Audit;
DROP TABLE IF EXISTS parts.DOG_Assessment_Response; DROP TABLE IF EXISTS parts.DOG_Assessment_Response;
@@ -181,6 +187,11 @@ DROP TABLE IF EXISTS parts.CORE_File_Type;
DROP TABLE IF EXISTS parts.CORE_Msg_Error_Type; DROP TABLE IF EXISTS parts.CORE_Msg_Error_Type;
-- Stored Procedures -- Stored Procedures
DROP PROCEDURE IF EXISTS parts.p_ph_test_get_many_contact_form;
DROP PROCEDURE IF EXISTS parts.p_ph_get_many_contact_form;
DROP PROCEDURE IF EXISTS parts.p_ph_test_save_contact_form;
DROP PROCEDURE IF EXISTS parts.p_ph_save_contact_form;
DROP PROCEDURE IF EXISTS parts.p_dog_test_get_many_dog_command; DROP PROCEDURE IF EXISTS parts.p_dog_test_get_many_dog_command;
DROP PROCEDURE IF EXISTS parts.p_dog_test_get_many_command; DROP PROCEDURE IF EXISTS parts.p_dog_test_get_many_command;
DROP PROCEDURE IF EXISTS parts.p_dog_get_many_command; DROP PROCEDURE IF EXISTS parts.p_dog_get_many_command;

View File

@@ -1,6 +1,8 @@
USE parts; USE parts;
-- DROP TABLE IF EXISTS parts.DOG_Assessment_Temp;
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
FROM INFORMATION_SCHEMA.TABLES FROM INFORMATION_SCHEMA.TABLES
WHERE WHERE
@@ -17,7 +19,7 @@ CREATE TABLE IF NOT EXISTS parts.DOG_Assessment_Temp (
, id_user_handler INT , id_user_handler INT
, notes TEXT , notes TEXT
, temperature_celcius DECIMAL(5, 2) , temperature_celcius DECIMAL(5, 2)
-- , difficulty_level DOUBLE , difficulty_level DOUBLE
, active BIT , active BIT
, does_meet_id_filters BIT , does_meet_id_filters BIT

View File

@@ -0,0 +1,19 @@
USE parts;
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
FROM INFORMATION_SCHEMA.TABLES
WHERE
TABLE_SCHEMA = 'parts'
AND TABLE_NAME = 'PH_Contact_Form_Change_Set'
;
CREATE TABLE IF NOT EXISTS parts.PH_Contact_Form_Change_Set (
id_change_set INT NOT NULL AUTO_INCREMENT PRIMARY KEY
, comment VARCHAR(500)
, updated_last_on DATETIME
, id_user_updated_last_by INT
, CONSTRAINT FK_PH_Contact_Form_Change_Set_id_user_updated_last_by
FOREIGN KEY (id_user_updated_last_by)
REFERENCES parts.DOG_User(id_user)
);

View File

@@ -0,0 +1,28 @@
USE parts;
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
FROM INFORMATION_SCHEMA.TABLES
WHERE
TABLE_SCHEMA = 'parts'
AND TABLE_NAME = 'PH_Contact_Form'
;
CREATE TABLE IF NOT EXISTS parts.PH_Contact_Form (
id_contact_form INT NOT NULL AUTO_INCREMENT PRIMARY KEY
, email VARCHAR(255) NOT NULL
, name_contact VARCHAR(255) NOT NULL
, name_company VARCHAR(255) NOT NULL
, message TEXT NOT NULL
, receive_marketing_communications BIT NOT NULL DEFAULT 0
, active BIT NOT NULL DEFAULT 1
, created_on DATETIME
, id_user_created_by INT
, CONSTRAINT FK_PH_Contact_Form_id_user_created_by
FOREIGN KEY (id_user_created_by)
REFERENCES parts.DOG_User(id_user)
, id_change_set INT
, CONSTRAINT FK_PH_Contact_Form_id_change_set
FOREIGN KEY (id_change_set)
REFERENCES parts.PH_Contact_Form_Change_Set(id_change_set)
);

View File

@@ -0,0 +1,24 @@
USE parts;
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
FROM INFORMATION_SCHEMA.TABLES
WHERE
TABLE_SCHEMA = 'parts'
AND TABLE_NAME = 'PH_Contact_Form_Audit'
;
CREATE TABLE IF NOT EXISTS parts.PH_Contact_Form_Audit (
id_audit INT NOT NULL AUTO_INCREMENT PRIMARY KEY
, id_contact_form INT NOT NULL
, CONSTRAINT FK_PH_Contact_Form_Audit_id_contact_form
FOREIGN KEY (id_contact_form)
REFERENCES parts.PH_Contact_Form(id_contact_form)
, name_field VARCHAR(50) NOT NULL
, value_prev TEXT
, value_new TEXT
, id_change_set INT NOT NULL
, CONSTRAINT FK_PH_Contact_Form_Audit_id_change_set
FOREIGN KEY (id_change_set)
REFERENCES parts.PH_Contact_Form_Change_Set(id_change_set)
);

View File

@@ -0,0 +1,21 @@
USE parts;
SELECT CONCAT('WARNING: Table ', TABLE_SCHEMA, '.', TABLE_NAME, ' already exists.') AS msg_warning
FROM INFORMATION_SCHEMA.TABLES
WHERE
TABLE_SCHEMA = 'parts'
AND TABLE_NAME = 'PH_Contact_Form_Temp'
;
CREATE TABLE IF NOT EXISTS parts.PH_Contact_Form_Temp (
id_temp INT NOT NULL PRIMARY KEY AUTO_INCREMENT
, id_contact_form INT
, email VARCHAR(255)
, name_contact VARCHAR(255)
, name_company VARCHAR(255)
, message TEXT
, receive_marketing_communications BIT
, active BIT
, guid BINARY(36)
);

View File

@@ -0,0 +1,14 @@
USE parts;
DROP TRIGGER IF EXISTS parts.before_insert_PH_Contact_Form_Change_Set;
DELIMITER //
CREATE TRIGGER parts.before_insert_PH_Contact_Form_Change_Set
BEFORE INSERT ON parts.PH_Contact_Form_Change_Set
FOR EACH ROW
BEGIN
IF NEW.updated_last_on <=> NULL THEN
SET NEW.updated_last_on = NOW();
END IF;
END //
DELIMITER ;

View File

@@ -0,0 +1,58 @@
USE parts;
DROP TRIGGER IF EXISTS parts.before_insert_PH_Contact_Form;
DROP TRIGGER IF EXISTS parts.before_update_PH_Contact_Form;
DELIMITER //
CREATE TRIGGER parts.before_insert_PH_Contact_Form
BEFORE INSERT ON parts.PH_Contact_Form
FOR EACH ROW
BEGIN
SET NEW.created_on := IFNULL(NEW.created_on, NOW());
END //
DELIMITER ;
DELIMITER //
CREATE TRIGGER parts.before_update_PH_Contact_Form
BEFORE UPDATE ON parts.PH_Contact_Form
FOR EACH ROW
BEGIN
IF OLD.id_change_set <=> NEW.id_change_set THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'New change Set ID must be provided.';
END IF;
INSERT INTO parts.PH_Contact_Form_Audit (
id_contact_form,
name_field,
value_prev,
value_new,
id_change_set
)
-- Changed email
SELECT NEW.id_contact_form, 'email', OLD.email, NEW.email, NEW.id_change_set
WHERE NOT OLD.email <=> NEW.email
UNION
-- Changed name_contact
SELECT NEW.id_contact_form, 'name_contact', OLD.name_contact, NEW.name_contact, NEW.id_change_set
WHERE NOT OLD.name_contact <=> NEW.name_contact
UNION
-- Changed name_company
SELECT NEW.id_contact_form, 'name_company', OLD.name_company, NEW.name_company, NEW.id_change_set
WHERE NOT OLD.name_company <=> NEW.name_company
UNION
-- Changed message
SELECT NEW.id_contact_form, 'message', OLD.message, NEW.message, NEW.id_change_set
WHERE NOT OLD.message <=> NEW.message
UNION
-- Changed receive_marketing_communications
SELECT NEW.id_contact_form, 'receive_marketing_communications', CONVERT(CONVERT(OLD.receive_marketing_communications, SIGNED), CHAR), CONVERT(CONVERT(NEW.receive_marketing_communications, SIGNED), CHAR), NEW.id_change_set
WHERE NOT (OLD.receive_marketing_communications <=> NEW.receive_marketing_communications)
UNION
-- Changed active
SELECT NEW.id_contact_form, 'active', CONVERT(CONVERT(OLD.active, SIGNED), CHAR), CONVERT(CONVERT(NEW.active, SIGNED), CHAR), NEW.id_change_set
WHERE NOT (OLD.active <=> NEW.active)
;
END //
DELIMITER ;

View File

@@ -0,0 +1,552 @@
USE parts;
DROP PROCEDURE IF EXISTS parts.p_dog_save_assessment;
DELIMITER //
CREATE PROCEDURE parts.p_dog_save_assessment (
IN a_comment VARCHAR(500),
IN a_guid BINARY(36),
IN a_id_user INT,
IN a_debug BIT
)
BEGIN
DECLARE v_can_admin BIT;
DECLARE v_can_create BIT;
DECLARE v_code_type_error_bad_data VARCHAR(100);
DECLARE v_id_access_level_edit INT;
DECLARE v_id_change_set INT;
DECLARE v_id_permission_dog_new INT;
DECLARE v_id_type_error_bad_data INT;
DECLARE v_time_start TIMESTAMP(6);
DECLARE exit handler for SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
@sqlstate = RETURNED_SQLSTATE
, @errno = MYSQL_ERRNO
, @text = MESSAGE_TEXT
;
ROLLBACK;
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_Msg_Error (
id_error INT NOT NULL PRIMARY KEY AUTO_INCREMENT
, id_type INT NULL
, code VARCHAR(250)
, msg TEXT NOT NULL
);
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
MET.id_type
, @errno
, @text
FROM parts.CORE_Msg_Error_Type MET
WHERE MET.code = 'MYSQL_ERROR'
;
SELECT
t_ERROR.id_error
, t_ERROR.id_type
, t_ERROR.code
, ERROR_TYPE.name
, ERROR_TYPE.description
, ERROR_TYPE.is_breaking_error
, ERROR_TYPE.background_colour
, ERROR_TYPE.text_colour
, t_ERROR.msg
FROM tmp_Msg_Error t_ERROR
INNER JOIN parts.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type
;
DROP TABLE IF EXISTS tmp_Msg_Error;
END;
SET SESSION group_concat_max_len=15000;
SET v_time_start := CURRENT_TIMESTAMP(6);
SET v_code_type_error_bad_data := 'BAD_DATA';
SET v_id_type_error_bad_data := (SELECT ERROR_TYPE.id_type FROM parts.CORE_Msg_Error_Type ERROR_TYPE WHERE ERROR_TYPE.code = v_code_type_error_bad_data LIMIT 1);
SET v_id_permission_dog_new := (SELECT PERMISSION.id_permission FROM parts.DOG_Permission PERMISSION WHERE PERMISSION.code = 'DOG_CREATE' LIMIT 1);
SET v_id_access_level_edit := (SELECT ACCESS_LEVEL.id_access_level FROM parts.DOG_Access_Level ACCESS_LEVEL WHERE ACCESS_LEVEL.code = 'EDIT' LIMIT 1);
CALL parts.p_core_validate_guid ( a_guid );
DROP TABLE IF EXISTS tmp_Assessment_Copy;
DROP TABLE IF EXISTS tmp_Assessment;
CREATE TEMPORARY TABLE tmp_Assessment (
id_temp INT
, id_assessment INT
, id_weather INT
, id_lighting_level INT
, id_location INT
, id_user_handler INT
, notes TEXT
, temperature_celcius DECIMAL(5, 2)
, difficulty_level FLOAT
, active BIT
, is_new BIT
, name_error VARCHAR(250)
);
CREATE TEMPORARY TABLE tmp_Assessment_Copy (
id_temp INT
, id_assessment INT
, id_weather INT
, id_lighting_level INT
, id_location INT
, id_user_handler INT
, notes TEXT
, temperature_celcius DECIMAL(5, 2)
, difficulty_level FLOAT
, active BIT
, is_new BIT
, name_error VARCHAR(250)
);
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_Msg_Error (
id_error INT NOT NULL PRIMARY KEY AUTO_INCREMENT
, id_type INT NULL
, code VARCHAR(250)
, msg TEXT NOT NULL
);
-- Get data from Temp table
INSERT INTO tmp_Assessment (
id_temp
, id_assessment
, id_weather
, id_lighting_level
, id_location
, id_user_handler
, notes
, temperature_celcius
, difficulty_level
, active
, is_new
)
SELECT
ASSESSMENT_T.id_temp
, ASSESSMENT_T.id_assessment
, COALESCE(
ASSESSMENT_T.id_weather
, ASSESSMENT.id_weather
) AS id_weather
, COALESCE(
ASSESSMENT_T.id_lighting_level
, ASSESSMENT.id_lighting_level
) AS id_lighting_level
, COALESCE(
ASSESSMENT_T.id_location
, ASSESSMENT.id_location
) AS id_location
, COALESCE(
ASSESSMENT_T.id_user_handler
, ASSESSMENT.id_user_handler
) AS id_user_handler
, ASSESSMENT_T.notes
, ASSESSMENT_T.temperature_celcius
, ASSESSMENT_T.difficulty_level
, COALESCE(ASSESSMENT_T.active, 1) AS active
, CASE WHEN COALESCE(ASSESSMENT_T.id_assessment, 0) < 1 THEN 1 ELSE 0 END AS is_new
FROM parts.DOG_Assessment_Temp ASSESSMENT_T
LEFT JOIN parts.DOG_Assessment ASSESSMENT ON ASSESSMENT_T.id_assessment = ASSESSMENT.id_assessment
WHERE ASSESSMENT_T.guid = a_guid
;
IF a_debug = 1 THEN
SELECT 'Assessment_Temp records';
SELECT * FROM tmp_Assessment;
SELECT COUNT(*) FROM tmp_Assessment;
END IF;
-- Error names
UPDATE tmp_Assessment t_ASSESSMENT
LEFT JOIN parts.DOG_Assessment ASSESSMENT ON t_ASSESSMENT.id_assessment = ASSESSMENT.id_assessment
SET t_ASSESSMENT.name_error = CONCAT(
CONVERT(COALESCE(t_ASSESSMENT.created_on, ASSESSMENT.created_on, v_time_start), CHAR)
, CASE WHEN t_ASSESSMENT.notes IS NOT NULL THEN CONCAT(' - ', t_ASSESSMENT.notes) ELSE '' END
/*
COALESCE(WEATHER.name, '(No Weather)')
, ' - '
, COALESCE(LIGHTING_LEVEL.name, '(No Lighting Level)')
, ' - '
, COALESCE(LOCATIONS.name, '(No Location)')
, ' - '
, COALESCE(CONCAT(USER_HANDLER.firstname, ' ', USER_HANDLER.surname), '(No User Handler)')
, ' - x'
, CONVERT(COALESCE(t_ASSESSMENT.quantity, 0), CHAR)
*/
)
;
IF a_debug = 1 THEN
SELECT 'After set name_error';
SELECT * FROM tmp_Assessment;
SELECT COUNT(*) FROM tmp_Assessment;
END IF;
-- Validation
-- Missing mandatory fields
-- id_weather
IF EXISTS (
SELECT *
FROM tmp_Assessment t_ASSESSMENT
LEFT JOIN demo.DOG_Weather WEATHER ON t_ASSESSMENT.id_weather = WEATHER.id_weather
WHERE
ISNULL(t_ASSESSMENT.id_weather)
OR ISNULL(WEATHER.id_weather)
OR WEATHER.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Dog Weather Assessment(s) do not have a valid Weather: ', GROUP_CONCAT(t_ASSESSMENT.name_error SEPARATOR ', ')) AS msg
FROM tmp_Assessment t_ASSESSMENT
LEFT JOIN parts.DOG_Weather WEATHER ON t_ASSESSMENT.id_weather = WEATHER.id_weather
WHERE
ISNULL(t_ASSESSMENT.id_weather)
OR ISNULL(WEATHER.id_weather)
OR WEATHER.active = 0
;
END IF;
-- id_lighting_level
IF EXISTS (
SELECT *
FROM tmp_Assessment t_ASSESSMENT
LEFT JOIN demo.DOG_Lighting_Level LIGHTING_LEVEL ON t_ASSESSMENT.id_lighting_level = LIGHTING_LEVEL.id_lighting_level
WHERE
ISNULL(t_ASSESSMENT.id_lighting_level)
OR ISNULL(LIGHTING_LEVEL.id_lighting_level)
OR LIGHTING_LEVEL.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Dog Lighting_Level Assessment(s) do not have a valid Lighting_Level: ', GROUP_CONCAT(t_ASSESSMENT.name_error SEPARATOR ', ')) AS msg
FROM tmp_Assessment t_ASSESSMENT
LEFT JOIN parts.DOG_Lighting_Level LIGHTING_LEVEL ON t_ASSESSMENT.id_lighting_level = LIGHTING_LEVEL.id_lighting_level
WHERE
ISNULL(t_ASSESSMENT.id_lighting_level)
OR ISNULL(LIGHTING_LEVEL.id_lighting_level)
OR LIGHTING_LEVEL.active = 0
;
END IF;
-- id_location
IF EXISTS (
SELECT *
FROM tmp_Assessment t_ASSESSMENT
LEFT JOIN demo.DOG_Location LOCATION ON t_ASSESSMENT.id_location = LOCATION.id_location
WHERE
ISNULL(t_ASSESSMENT.id_location)
OR ISNULL(LOCATION.id_location)
OR LOCATION.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Dog Location Assessment(s) do not have a valid Location: ', GROUP_CONCAT(t_ASSESSMENT.name_error SEPARATOR ', ')) AS msg
FROM tmp_Assessment t_ASSESSMENT
LEFT JOIN parts.DOG_Location LOCATION ON t_ASSESSMENT.id_location = LOCATION.id_location
WHERE
ISNULL(t_ASSESSMENT.id_location)
OR ISNULL(LOCATION.id_location)
OR LOCATION.active = 0
;
END IF;
-- id_user_handler
IF EXISTS (
SELECT *
FROM tmp_Assessment t_ASSESSMENT
LEFT JOIN demo.DOG_User USER_HANDLER ON t_ASSESSMENT.id_user_handler = USER_HANDLER.id_user_handler
WHERE
ISNULL(t_ASSESSMENT.id_user_handler)
OR ISNULL(USER_HANDLER.id_user_handler)
OR USER_HANDLER.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Dog User_Handler Assessment(s) do not have a valid User_Handler: ', GROUP_CONCAT(t_ASSESSMENT.name_error SEPARATOR ', ')) AS msg
FROM tmp_Assessment t_ASSESSMENT
LEFT JOIN parts.DOG_User USER_HANDLER ON t_ASSESSMENT.id_user_handler = USER_HANDLER.id_user_handler
WHERE
ISNULL(t_ASSESSMENT.id_user_handler)
OR ISNULL(USER_HANDLER.id_user_handler)
OR USER_HANDLER.active = 0
;
END IF;
-- Permissions
-- Can Create
CALL parts.p_dog_calc_user(
a_guid
, 0 -- get_all_user
, 0 -- get_inactive_user
, a_id_user -- ids_user
, '' -- a_auth0_ids_user
, '' -- a_names_user
, '' -- a_emails_user
, 1 -- a_require_all_id_search_filters_met
, 1 -- a_require_any_id_search_filters_met
, 0 -- a_require_all_non_id_search_filters_met
, 0 -- a_require_any_non_id_search_filters_met
, v_id_permission_dog_new -- ids_permission
, v_id_access_level_edit -- ids_access_level
, 0 -- a_show_errors
, 0 -- a_debug
);
SELECT
IFNULL(CU_T.has_access, 0)
INTO
v_can_create
FROM parts.DOG_Calc_User_Temp CU_T
WHERE CU_T.GUID = a_guid
LIMIT 1
;
CALL parts.p_dog_clear_calc_user(
a_guid
, 0 -- a_debug
);
IF v_can_create = 0 THEN
DELETE t_ME
FROM tmp_Msg_Error t_ME
WHERE t_ME.id_type <> v_id_type_error_no_permission
;
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
VALUES (
v_id_type_error_no_permission
, v_code_type_error_no_permission
, 'You do not have permission to edit Assessments.'
)
;
END IF;
IF EXISTS (SELECT * FROM tmp_Msg_Error t_ERROR INNER JOIN parts.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type WHERE ERROR_TYPE.is_breaking_error = 1 LIMIT 1) THEN
IF a_debug = 1 THEN
SELECT * from tmp_Assessment;
END IF;
DELETE FROM tmp_Assessment;
END IF;
IF NOT EXISTS (SELECT * FROM tmp_Msg_Error t_ERROR INNER JOIN parts.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type WHERE ERROR_TYPE.is_breaking_error = 1 LIMIT 1) THEN
START TRANSACTION;
INSERT INTO parts.DOG_Dog_Change_Set (
comment
, id_user_updated_last_by
, updated_last_on
)
VALUES (
a_comment
, a_id_user
, v_time_start
)
;
SET v_id_change_set := LAST_INSERT_ID();
UPDATE parts.DOG_Assessment ASSESSMENT
INNER JOIN tmp_Assessment t_ASSESSMENT
ON ASSESSMENT.id_assessment = t_ASSESSMENT.id_assessment
AND t_ASSESSMENT.is_new = 0
SET
ASSESSMENT.id_weather = t_ASSESSMENT.id_weather
, ASSESSMENT.id_lighting_level = t_ASSESSMENT.id_lighting_level
, ASSESSMENT.id_location = t_ASSESSMENT.id_location
, ASSESSMENT.id_user_handler = t_ASSESSMENT.id_user_handler
, ASSESSMENT.temperature_celcius = t_ASSESSMENT.temperature_celcius
, ASSESSMENT.difficulty_level = t_ASSESSMENT.difficulty_level
, ASSESSMENT.notes = t_ASSESSMENT.notes
, ASSESSMENT.active = t_ASSESSMENT.active
, ASSESSMENT.id_change_set = v_id_change_set
;
INSERT INTO parts.DOG_Assessment (
id_weather
, id_lighting_level
, id_location
, id_user_handler
, temperature_celcius
, difficulty_level
, notes
, active
, id_user_created_by
, created_on
)
SELECT
t_ASSESSMENT.id_weather AS id_weather
, t_ASSESSMENT.id_lighting_level AS id_lighting_level
, t_ASSESSMENT.id_location AS id_location
, t_ASSESSMENT.id_user_handler AS id_user_handler
, t_ASSESSMENT.temperature_celcius AS temperature_celcius
, t_ASSESSMENT.difficulty_level AS difficulty_level
, t_ASSESSMENT.notes AS notes
, t_ASSESSMENT.active AS active
, a_id_user AS created_by
, v_time_start AS created_on
FROM tmp_Assessment t_ASSESSMENT
WHERE
t_ASSESSMENT.is_new = 1
AND t_ASSESSMENT.active = 1
;
COMMIT;
END IF;
START TRANSACTION;
DELETE FROM parts.DOG_Assessment_Temp
WHERE GUID = a_guid
;
COMMIT;
-- Errors
SELECT
t_ERROR.id_error
, t_ERROR.id_type
, t_ERROR.code
, ERROR_TYPE.name
, ERROR_TYPE.description
, ERROR_TYPE.is_breaking_error
, ERROR_TYPE.background_colour
, ERROR_TYPE.text_colour
, t_ERROR.msg
FROM tmp_Msg_Error t_ERROR
INNER JOIN parts.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type
;
IF a_debug = 1 THEN
SELECT * FROM tmp_Assessment;
END IF;
DROP TEMPORARY TABLE tmp_Assessment;
DROP TEMPORARY TABLE tmp_Msg_Error;
IF a_debug = 1 THEN
CALL parts.p_core_debug_timing_reporting ( v_time_start );
END IF;
END //
DELIMITER ;
/*
'ripplesipplenippletippledipplekipple'
DELETE FROM parts.DOG_Assessment WHERE id_assessment > 740;
* /
delete
from parts.DOG_Assessment_Audit
where id_assessment > 768
;
delete
from parts.DOG_Assessment
where id_assessment > 768
;
delete
from parts.DOG_Assessment_Temp
;
select
*
-- COUNT(*)
-- delete
from parts.DOG_Assessment_Temp
;
select COUNT(*)
from parts.DOG_Assessment_Temp
;
select
*
-- COUNT(*)
-- delete
from parts.DOG_Assessment
;
select COUNT(*)
from parts.DOG_Assessment
;
INSERT INTO parts.DOG_Assessment_Temp (
id_assessment
, id_dog
, id_command
, hand_signal_description
, notes
, active
, guid
)
VALUES (
-1 -- id_assessment
, 1 -- id_dog
, 1 -- id_command
, 'Test deez noots' -- hand_signal_description
, NULL -- notes
, 1 -- active
, 'ripplesipplenippletippledipplekipple'
);
CALL parts.p_dog_save_assessment (
'nipples'
, 'ripplesipplenippletippledipplekipple'
, 1
, 1
);
select
*
-- COUNT(*)
-- delete
from parts.DOG_Assessment_Temp
;
select COUNT(*)
from parts.DOG_Assessment_Temp
;
select
*
-- COUNT(*)
-- delete
from parts.DOG_Assessment
;
select COUNT(*)
from parts.DOG_Assessment
;
*/

View File

@@ -1,693 +0,0 @@
USE parts;
DROP PROCEDURE IF EXISTS parts.p_dog_save_dog_command_link;
DELIMITER //
CREATE PROCEDURE parts.p_dog_save_dog_command_link (
IN a_comment VARCHAR(500),
IN a_guid BINARY(36),
IN a_id_user INT,
IN a_debug BIT
)
BEGIN
DECLARE v_can_admin BIT;
DECLARE v_can_create BIT;
DECLARE v_code_type_error_bad_data VARCHAR(100);
DECLARE v_id_access_level_edit INT;
DECLARE v_id_change_set INT;
DECLARE v_id_permission_dog_new INT;
DECLARE v_id_type_error_bad_data INT;
DECLARE v_time_start TIMESTAMP(6);
DECLARE exit handler for SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
@sqlstate = RETURNED_SQLSTATE
, @errno = MYSQL_ERRNO
, @text = MESSAGE_TEXT
;
ROLLBACK;
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_Msg_Error (
id_error INT NOT NULL PRIMARY KEY AUTO_INCREMENT
, id_type INT NULL
, code VARCHAR(250)
, msg TEXT NOT NULL
);
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
MET.id_type
, @errno
, @text
FROM parts.CORE_Msg_Error_Type MET
WHERE MET.code = 'MYSQL_ERROR'
;
SELECT
t_ERROR.id_error
, t_ERROR.id_type
, t_ERROR.code
, ERROR_TYPE.name
, ERROR_TYPE.description
, ERROR_TYPE.is_breaking_error
, ERROR_TYPE.background_colour
, ERROR_TYPE.text_colour
, t_ERROR.msg
FROM tmp_Msg_Error t_ERROR
INNER JOIN parts.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type
;
DROP TABLE IF EXISTS tmp_Msg_Error;
END;
SET SESSION group_concat_max_len=15000;
SET v_time_start := CURRENT_TIMESTAMP(6);
SET v_code_type_error_bad_data := 'BAD_DATA';
SET v_id_type_error_bad_data := (SELECT ERROR_TYPE.id_type FROM parts.CORE_Msg_Error_Type ERROR_TYPE WHERE ERROR_TYPE.code = v_code_type_error_bad_data LIMIT 1);
SET v_id_permission_dog_new := (SELECT PERMISSION.id_permission FROM parts.DOG_Permission PERMISSION WHERE PERMISSION.code = 'DOG_CREATE' LIMIT 1);
SET v_id_access_level_edit := (SELECT ACCESS_LEVEL.id_access_level FROM parts.DOG_Access_Level ACCESS_LEVEL WHERE ACCESS_LEVEL.code = 'EDIT' LIMIT 1);
CALL parts.p_core_validate_guid ( a_guid );
DROP TABLE IF EXISTS tmp_Dog_Command_Link_Copy;
DROP TABLE IF EXISTS tmp_Dog_Command_Link;
CREATE TEMPORARY TABLE tmp_Dog_Command_Link (
id_temp INT
, id_link INT
, id_dog INT
, id_command INT
, hand_signal_description TEXT
, notes TEXT
, active BIT
, is_new BIT
, name_error VARCHAR(250)
);
CREATE TEMPORARY TABLE tmp_Dog_Command_Link_Copy (
id_temp INT
, id_link INT
, id_dog INT
, id_command INT
, hand_signal_description TEXT
, notes TEXT
, active BIT
, is_new BIT
, name_error VARCHAR(250)
);
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_Msg_Error (
id_error INT NOT NULL PRIMARY KEY AUTO_INCREMENT
, id_type INT NULL
, code VARCHAR(250)
, msg TEXT NOT NULL
);
-- Get data from Temp table
INSERT INTO tmp_Dog_Command_Link (
id_temp
, id_link
, id_dog
, id_command
, hand_signal_description
, notes
, active
, is_new
)
SELECT
DOG_COMMAND_LINK_T.id_temp
, COALESCE(DOG_COMMAND_LINK.id_link, DOG_COMMAND_LINK_T.id_link)
, COALESCE(
DOG_COMMAND_LINK_T.id_dog
, DOG_COMMAND_LINK.id_dog
) AS id_dog
, COALESCE(
DOG_COMMAND_LINK_T.id_command
, DOG_COMMAND_LINK.id_command
) AS id_command
/*
, NULLIF(
COALESCE(
DOG_COMMAND_LINK_T.hand_signal_description
, DOG_COMMAND_LINK.hand_signal_description
)
, ''
) AS hand_signal_description
, NULLIF(
COALESCE(
DOG_COMMAND_LINK_T.notes
, DOG_COMMAND_LINK.notes
)
, ''
) AS notes
*/
, COALESCE(
DOG_COMMAND_LINK_T.hand_signal_description
, DOG_COMMAND_LINK.hand_signal_description
) AS hand_signal_description
, COALESCE(
DOG_COMMAND_LINK_T.notes
, DOG_COMMAND_LINK.notes
) AS notes
, COALESCE(DOG_COMMAND_LINK_T.active, 1) AS active
, CASE WHEN COALESCE(DOG_COMMAND_LINK.id_link, DOG_COMMAND_LINK_T.id_link, 0) < 1 THEN 1 ELSE 0 END AS is_new
FROM parts.DOG_Dog_Command_Link_Temp DOG_COMMAND_LINK_T
LEFT JOIN parts.DOG_Dog_Command_Link DOG_COMMAND_LINK
ON DOG_COMMAND_LINK_T.id_link = DOG_COMMAND_LINK.id_link
OR (
DOG_COMMAND_LINK_T.id_dog = DOG_COMMAND_LINK.id_dog
AND DOG_COMMAND_LINK_T.id_command = DOG_COMMAND_LINK.id_command
AND (
DOG_COMMAND_LINK.hand_signal_description IS NULL
OR DOG_COMMAND_LINK_T.hand_signal_description <=> DOG_COMMAND_LINK.hand_signal_description
)
AND (
DOG_COMMAND_LINK.notes IS NULL
OR DOG_COMMAND_LINK_T.notes <=> DOG_COMMAND_LINK.notes
)
)
WHERE DOG_COMMAND_LINK_T.guid = a_guid
;
IF a_debug = 1 THEN
SELECT 'Dog_Command_Link_Temp records';
SELECT * FROM tmp_Dog_Command_Link;
SELECT COUNT(*) FROM tmp_Dog_Command_Link;
END IF;
-- Error names
UPDATE tmp_Dog_Command_Link t_DOG_COMMAND_LINK
LEFT JOIN parts.DOG_Dog DOG ON t_DOG_COMMAND_LINK.id_dog = DOG.id_dog
LEFT JOIN parts.DOG_Command COMMAND ON t_DOG_COMMAND_LINK.id_command = COMMAND.id_command
SET t_DOG_COMMAND_LINK.name_error = CASE WHEN
ISNULL(DOG.id_dog)
AND ISNULL(COMMAND.id_command)
THEN COALESCE(t_DOG_COMMAND_LINK.hand_signal_description, t_DOG_COMMAND_LINK.notes, '(No Dog Command Link)')
ELSE CONCAT(
COALESCE(DOG.name, t_DOG_COMMAND_LINK.id_dog, '(No Dog)')
, ' - '
, COALESCE(COMMAND.name, t_DOG_COMMAND_LINK.id_command, '(No Command)')
) END
;
IF a_debug = 1 THEN
SELECT 'After set name_error';
SELECT * FROM tmp_Dog_Command_Link;
SELECT COUNT(*) FROM tmp_Dog_Command_Link;
END IF;
/*
-- Missing Dog Command Link Ids
UPDATE tmp_Dog_Command_Link t_DOG_COMMAND_LINK
LEFT JOIN parts.DOG_Dog_Command_Link DOG_COMMAND_LINK
-- ON t_DOG_COMMAND_LINK.id_link = DOG_COMMAND_LINK.id_link
ON t_DOG_COMMAND_LINK.id_dog = DOG_COMMAND_LINK.id_dog
AND t_DOG_COMMAND_LINK.id_command = DOG_COMMAND_LINK.id_command
SET
t_DOG_COMMAND_LINK.id_link = DOG_COMMAND_LINK.id_link
, t_DOG_COMMAND_LINK.is_new = 0
WHERE
IFNULL(t_DOG_COMMAND_LINK.id_link, 0) < 1
AND NOT ISNULL(DOG_COMMAND_LINK.id_link)
;
IF a_debug = 1 THEN
SELECT 'After set missing id_link';
SELECT * FROM tmp_Dog_Command_Link;
SELECT COUNT(*) FROM tmp_Dog_Command_Link;
END IF;
*/
-- Validation
-- Missing mandatory fields
-- id_dog
IF EXISTS (
SELECT *
FROM tmp_Dog_Command_Link t_DOG_COMMAND_LINK
LEFT JOIN demo.DOG_Dog DOG ON t_DOG_COMMAND_LINK.id_dog = DOG.id_dog
WHERE
ISNULL(t_DOG_COMMAND_LINK.id_dog)
OR ISNULL(DOG.id_dog)
OR DOG.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Dog Command Link(s) do not have a valid Dog: ', GROUP_CONCAT(t_DOG_COMMAND_LINK.name_error SEPARATOR ', ')) AS msg
FROM tmp_Dog_Command_Link t_DOG_COMMAND_LINK
LEFT JOIN parts.DOG_Dog DOG ON t_DOG_COMMAND_LINK.id_dog = DOG.id_dog
WHERE
ISNULL(t_DOG_COMMAND_LINK.id_dog)
OR ISNULL(DOG.id_dog)
OR DOG.active = 0
;
END IF;
-- id_command
IF EXISTS (
SELECT *
FROM tmp_Dog_Command_Link t_DOG_COMMAND_LINK
LEFT JOIN demo.DOG_Command COMMAND ON t_DOG_COMMAND_LINK.id_command = COMMAND.id_command
WHERE
ISNULL(t_DOG_COMMAND_LINK.id_command)
OR ISNULL(COMMAND.id_command)
OR COMMAND.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Dog Command Link(s) do not have a valid Command: ', GROUP_CONCAT(t_DOG_COMMAND_LINK.name_error SEPARATOR ', ')) AS msg
FROM tmp_Dog_Command_Link t_DOG_COMMAND_LINK
LEFT JOIN parts.DOG_Command COMMAND ON t_DOG_COMMAND_LINK.id_command = COMMAND.id_command
WHERE
ISNULL(t_DOG_COMMAND_LINK.id_command)
OR ISNULL(COMMAND.id_command)
OR COMMAND.active = 0
;
END IF;
-- Duplicates
INSERT INTO tmp_Dog_Command_Link_Copy (
id_temp
, id_link
, id_dog
, id_command
, hand_signal_description
, notes
, active
, is_new
, name_error
)
SELECT
t_DOG_COMMAND_LINK.id_temp
, t_DOG_COMMAND_LINK.id_link
, t_DOG_COMMAND_LINK.id_dog
, t_DOG_COMMAND_LINK.id_command
, t_DOG_COMMAND_LINK.hand_signal_description
, t_DOG_COMMAND_LINK.notes
, t_DOG_COMMAND_LINK.active
, t_DOG_COMMAND_LINK.is_new
, t_DOG_COMMAND_LINK.name_error
FROM tmp_Dog_Command_Link t_DOG_COMMAND_LINK
;
IF a_debug = 1 THEN
SELECT COUNT(*) AS Count_Temp_Link FROM tmp_Dog_Command_Link;
SELECT COUNT(*) AS Count_Temp_Link_Copy FROM tmp_Dog_Command_Link_Copy;
WITH
Combined_Links AS (
SELECT
DOG_COMMAND_LINK.id_link
, DOG_COMMAND_LINK.id_dog
, DOG_COMMAND_LINK.id_command
, IFNULL(
t_DOG_COMMAND_LINK_COPY.name_error
, CONCAT(
COALESCE(DOG.name, t_DOG_COMMAND_LINK_COPY.id_dog, '(No Dog)')
, ' - '
, COALESCE(COMMAND.name, t_DOG_COMMAND_LINK_COPY.id_command, '(No Command)')
)
) AS name_error
FROM parts.DOG_Dog_Command_Link DOG_COMMAND_LINK
LEFT JOIN tmp_Dog_Command_Link_Copy t_DOG_COMMAND_LINK_COPY
ON DOG_COMMAND_LINK.id_dog = t_DOG_COMMAND_LINK_COPY.id_dog
AND DOG_COMMAND_LINK.id_command = t_DOG_COMMAND_LINK_COPY.id_command
INNER JOIN parts.DOG_Dog DOG ON DOG_COMMAND_LINK.id_dog = DOG.id_dog
INNER JOIN parts.DOG_Command COMMAND ON DOG_COMMAND_LINK.id_command = COMMAND.id_command
WHERE t_DOG_COMMAND_LINK_COPY.is_new = 1
UNION
SELECT
t_DOG_COMMAND_LINK.id_link
, t_DOG_COMMAND_LINK.id_dog
, t_DOG_COMMAND_LINK.id_command
, t_DOG_COMMAND_LINK.name_error
FROM tmp_Dog_Command_Link t_DOG_COMMAND_LINK
)
, Duplicate_Link_Row_Numbers AS (
SELECT
COMBINED_LINK.id_link
, COMBINED_LINK.id_dog
, COMBINED_LINK.id_command
, COMBINED_LINK.name_error
, ROW_NUMBER() OVER (PARTITION BY COMBINED_LINK.id_dog, COMBINED_LINK.id_command ORDER BY COMBINED_LINK.name_error ASC) AS index_link_as_duplicate
FROM Combined_Links COMBINED_LINK
)
SELECT *
FROM Duplicate_Link_Row_Numbers;
END IF;
IF EXISTS (
WITH
Combined_Links AS (
SELECT
DOG_COMMAND_LINK.id_link
, DOG_COMMAND_LINK.id_dog
, DOG_COMMAND_LINK.id_command
, IFNULL(
t_DOG_COMMAND_LINK_COPY.name_error
, CONCAT(
COALESCE(DOG.name, t_DOG_COMMAND_LINK_COPY.id_dog, '(No Dog)')
, ' - '
, COALESCE(COMMAND.name, t_DOG_COMMAND_LINK_COPY.id_command, '(No Command)')
)
) AS name_error
FROM parts.DOG_Dog_Command_Link DOG_COMMAND_LINK
LEFT JOIN tmp_Dog_Command_Link_Copy t_DOG_COMMAND_LINK_COPY
ON DOG_COMMAND_LINK.id_dog = t_DOG_COMMAND_LINK_COPY.id_dog
AND DOG_COMMAND_LINK.id_command = t_DOG_COMMAND_LINK_COPY.id_command
INNER JOIN parts.DOG_Dog DOG ON DOG_COMMAND_LINK.id_dog = DOG.id_dog
INNER JOIN parts.DOG_Command COMMAND ON DOG_COMMAND_LINK.id_command = COMMAND.id_command
WHERE t_DOG_COMMAND_LINK_COPY.is_new = 1
UNION
SELECT
t_DOG_COMMAND_LINK.id_link
, t_DOG_COMMAND_LINK.id_dog
, t_DOG_COMMAND_LINK.id_command
, t_DOG_COMMAND_LINK.name_error
FROM tmp_Dog_Command_Link t_DOG_COMMAND_LINK
)
, Duplicate_Link_Row_Numbers AS (
SELECT
COMBINED_LINK.id_link
, COMBINED_LINK.id_dog
, COMBINED_LINK.id_command
, COMBINED_LINK.name_error
, ROW_NUMBER() OVER (PARTITION BY COMBINED_LINK.id_dog, COMBINED_LINK.id_command ORDER BY COMBINED_LINK.name_error ASC) AS index_link_as_duplicate
FROM Combined_Links COMBINED_LINK
)
SELECT *
FROM Duplicate_Link_Row_Numbers DUPLICATE_LINK
WHERE DUPLICATE_LINK.index_link_as_duplicate > 1
GROUP BY DUPLICATE_LINK.id_dog, DUPLICATE_LINK.id_command
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
WITH
Combined_Links AS (
SELECT
DOG_COMMAND_LINK.id_link
, DOG_COMMAND_LINK.id_dog
, DOG_COMMAND_LINK.id_command
, IFNULL(
t_DOG_COMMAND_LINK_COPY.name_error
, CONCAT(
COALESCE(DOG.name, t_DOG_COMMAND_LINK_COPY.id_dog, '(No Dog)')
, ' - '
, COALESCE(COMMAND.name, t_DOG_COMMAND_LINK_COPY.id_command, '(No Command)')
)
) AS name_error
FROM parts.DOG_Dog_Command_Link DOG_COMMAND_LINK
LEFT JOIN tmp_Dog_Command_Link_Copy t_DOG_COMMAND_LINK_COPY
ON DOG_COMMAND_LINK.id_dog = t_DOG_COMMAND_LINK_COPY.id_dog
AND DOG_COMMAND_LINK.id_command = t_DOG_COMMAND_LINK_COPY.id_command
INNER JOIN parts.DOG_Dog DOG ON DOG_COMMAND_LINK.id_dog = DOG.id_dog
INNER JOIN parts.DOG_Command COMMAND ON DOG_COMMAND_LINK.id_command = COMMAND.id_command
WHERE t_DOG_COMMAND_LINK_COPY.is_new = 1
UNION
SELECT
t_DOG_COMMAND_LINK.id_link
, t_DOG_COMMAND_LINK.id_dog
, t_DOG_COMMAND_LINK.id_command
, t_DOG_COMMAND_LINK.name_error
FROM tmp_Dog_Command_Link t_DOG_COMMAND_LINK
)
, Duplicate_Link_Row_Numbers AS (
SELECT
COMBINED_LINK.id_link
, COMBINED_LINK.id_dog
, COMBINED_LINK.id_command
, COMBINED_LINK.name_error
, ROW_NUMBER() OVER (PARTITION BY COMBINED_LINK.id_dog, COMBINED_LINK.id_command ORDER BY COMBINED_LINK.name_error ASC) AS index_link_as_duplicate
FROM Combined_Links COMBINED_LINK
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('Attempt to create duplicate or overwrite existing Dog Command Links on: ', GROUP_CONCAT(DUPLICATE_LINK.name_error SEPARATOR ', ')) AS msg
FROM Duplicate_Link_Row_Numbers DUPLICATE_LINK
WHERE DUPLICATE_LINK.index_link_as_duplicate > 1
GROUP BY
DUPLICATE_LINK.id_dog
, DUPLICATE_LINK.id_command
;
END IF;
-- Permissions
-- Can Create
CALL parts.p_dog_calc_user(
a_guid
, 0 -- get_all_user
, 0 -- get_inactive_user
, a_id_user -- ids_user
, '' -- a_auth0_ids_user
, '' -- a_names_user
, '' -- a_emails_user
, 1 -- a_require_all_id_search_filters_met
, 1 -- a_require_any_id_search_filters_met
, 0 -- a_require_all_non_id_search_filters_met
, 0 -- a_require_any_non_id_search_filters_met
, v_id_permission_dog_new -- ids_permission
, v_id_access_level_edit -- ids_access_level
, 0 -- a_show_errors
, 0 -- a_debug
);
SELECT
IFNULL(CU_T.has_access, 0)
INTO
v_can_create
FROM parts.DOG_Calc_User_Temp CU_T
WHERE CU_T.GUID = a_guid
LIMIT 1
;
CALL parts.p_dog_clear_calc_user(
a_guid
, 0 -- a_debug
);
IF v_can_create = 0 THEN
DELETE t_ME
FROM tmp_Msg_Error t_ME
WHERE t_ME.id_type <> v_id_type_error_no_permission
;
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
VALUES (
v_id_type_error_no_permission
, v_code_type_error_no_permission
, 'You do not have permission to edit Commands.'
)
;
END IF;
IF EXISTS (SELECT * FROM tmp_Msg_Error t_ERROR INNER JOIN parts.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type WHERE ERROR_TYPE.is_breaking_error = 1 LIMIT 1) THEN
IF a_debug = 1 THEN
SELECT * from tmp_Dog_Command_Link;
END IF;
DELETE FROM tmp_Dog_Command_Link;
END IF;
IF NOT EXISTS (SELECT * FROM tmp_Msg_Error t_ERROR INNER JOIN parts.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type WHERE ERROR_TYPE.is_breaking_error = 1 LIMIT 1) THEN
START TRANSACTION;
INSERT INTO parts.DOG_Dog_Change_Set (
comment
, id_user_updated_last_by
, updated_last_on
)
VALUES (
a_comment
, a_id_user
, v_time_start
)
;
SET v_id_change_set := LAST_INSERT_ID();
UPDATE parts.DOG_Dog_Command_Link DOG_COMMAND_LINK
INNER JOIN tmp_Dog_Command_Link t_DOG_COMMAND_LINK
ON DOG_COMMAND_LINK.id_link = t_DOG_COMMAND_LINK.id_link
AND t_DOG_COMMAND_LINK.is_new = 0
SET
DOG_COMMAND_LINK.id_dog = t_DOG_COMMAND_LINK.id_dog
, DOG_COMMAND_LINK.id_command = t_DOG_COMMAND_LINK.id_command
, DOG_COMMAND_LINK.hand_signal_description = t_DOG_COMMAND_LINK.hand_signal_description
, DOG_COMMAND_LINK.notes = t_DOG_COMMAND_LINK.notes
, DOG_COMMAND_LINK.active = t_DOG_COMMAND_LINK.active
, DOG_COMMAND_LINK.id_change_set = v_id_change_set
;
INSERT INTO parts.DOG_Dog_Command_Link (
id_dog
, id_command
, hand_signal_description
, notes
, active
, id_user_created_by
, created_on
)
SELECT
t_DOG_COMMAND_LINK.id_dog AS id_dog
, t_DOG_COMMAND_LINK.id_command AS id_command
, t_DOG_COMMAND_LINK.hand_signal_description AS hand_signal_description
, t_DOG_COMMAND_LINK.notes AS notes
, t_DOG_COMMAND_LINK.active AS active
, a_id_user AS created_by
, v_time_start AS created_on
FROM tmp_Dog_Command_Link t_DOG_COMMAND_LINK
WHERE
t_DOG_COMMAND_LINK.is_new = 1
AND t_DOG_COMMAND_LINK.active = 1
;
COMMIT;
END IF;
START TRANSACTION;
DELETE FROM parts.DOG_Dog_Command_Link_Temp
WHERE GUID = a_guid
;
COMMIT;
-- Errors
SELECT
t_ERROR.id_error
, t_ERROR.id_type
, t_ERROR.code
, ERROR_TYPE.name
, ERROR_TYPE.description
, ERROR_TYPE.is_breaking_error
, ERROR_TYPE.background_colour
, ERROR_TYPE.text_colour
, t_ERROR.msg
FROM tmp_Msg_Error t_ERROR
INNER JOIN parts.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type
;
IF a_debug = 1 THEN
SELECT * FROM tmp_Dog_Command_Link;
END IF;
DROP TEMPORARY TABLE tmp_Dog_Command_Link;
DROP TEMPORARY TABLE tmp_Msg_Error;
IF a_debug = 1 THEN
CALL parts.p_core_debug_timing_reporting ( v_time_start );
END IF;
END //
DELIMITER ;
/*
'ripplesipplenippletippledipplekipple'
DELETE FROM parts.DOG_Dog_Command_Link WHERE id_link > 740;
* /
delete
from parts.DOG_Dog_Command_Link_Audit
where id_link > 768
;
delete
from parts.DOG_Dog_Command_Link
where id_link > 768
;
delete
from parts.DOG_Dog_Command_Link_Temp
;
select
*
-- COUNT(*)
-- delete
from parts.DOG_Dog_Command_Link_Temp
;
select COUNT(*)
from parts.DOG_Dog_Command_Link_Temp
;
select
*
-- COUNT(*)
-- delete
from parts.DOG_Dog_Command_Link
;
select COUNT(*)
from parts.DOG_Dog_Command_Link
;
INSERT INTO parts.DOG_Dog_Command_Link_Temp (
id_link
, id_dog
, id_command
, hand_signal_description
, notes
, active
, guid
)
VALUES (
-1 -- id_link
, 1 -- id_dog
, 1 -- id_command
, 'Test deez noots' -- hand_signal_description
, NULL -- notes
, 1 -- active
, 'ripplesipplenippletippledipplekipple'
);
CALL parts.p_dog_save_dog_command_link (
'nipples'
, 'ripplesipplenippletippledipplekipple'
, 1
, 1
);
select
*
-- COUNT(*)
-- delete
from parts.DOG_Dog_Command_Link_Temp
;
select COUNT(*)
from parts.DOG_Dog_Command_Link_Temp
;
select
*
-- COUNT(*)
-- delete
from parts.DOG_Dog_Command_Link
;
select COUNT(*)
from parts.DOG_Dog_Command_Link
;
*/

View File

@@ -0,0 +1,672 @@
USE parts;
DROP PROCEDURE IF EXISTS parts.p_dog_save_distraction;
DELIMITER //
CREATE PROCEDURE parts.p_dog_save_distraction (
IN a_comment VARCHAR(500),
IN a_guid BINARY(36),
IN a_id_user INT,
IN a_debug BIT
)
BEGIN
DECLARE v_can_admin BIT;
DECLARE v_can_create BIT;
DECLARE v_code_type_error_bad_data VARCHAR(100);
DECLARE v_id_access_level_edit INT;
DECLARE v_id_change_set INT;
DECLARE v_id_permission_dog_new INT;
DECLARE v_id_type_error_bad_data INT;
DECLARE v_time_start TIMESTAMP(6);
DECLARE exit handler for SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
@sqlstate = RETURNED_SQLSTATE
, @errno = MYSQL_ERRNO
, @text = MESSAGE_TEXT
;
ROLLBACK;
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_Msg_Error (
id_error INT NOT NULL PRIMARY KEY AUTO_INCREMENT
, id_type INT NULL
, code VARCHAR(250)
, msg TEXT NOT NULL
);
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
MET.id_type
, @errno
, @text
FROM parts.CORE_Msg_Error_Type MET
WHERE MET.code = 'MYSQL_ERROR'
;
SELECT
t_ERROR.id_error
, t_ERROR.id_type
, t_ERROR.code
, ERROR_TYPE.name
, ERROR_TYPE.description
, ERROR_TYPE.is_breaking_error
, ERROR_TYPE.background_colour
, ERROR_TYPE.text_colour
, t_ERROR.msg
FROM tmp_Msg_Error t_ERROR
INNER JOIN parts.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type
;
DROP TABLE IF EXISTS tmp_Msg_Error;
END;
SET SESSION group_concat_max_len=15000;
SET v_time_start := CURRENT_TIMESTAMP(6);
SET v_code_type_error_bad_data := 'BAD_DATA';
SET v_id_type_error_bad_data := (SELECT ERROR_TYPE.id_type FROM parts.CORE_Msg_Error_Type ERROR_TYPE WHERE ERROR_TYPE.code = v_code_type_error_bad_data LIMIT 1);
SET v_id_permission_dog_new := (SELECT PERMISSION.id_permission FROM parts.DOG_Permission PERMISSION WHERE PERMISSION.code = 'DOG_CREATE' LIMIT 1);
SET v_id_access_level_edit := (SELECT ACCESS_LEVEL.id_access_level FROM parts.DOG_Access_Level ACCESS_LEVEL WHERE ACCESS_LEVEL.code = 'EDIT' LIMIT 1);
CALL parts.p_core_validate_guid ( a_guid );
DROP TABLE IF EXISTS tmp_Distraction_Copy;
DROP TABLE IF EXISTS tmp_Distraction;
CREATE TEMPORARY TABLE tmp_Distraction (
id_temp INT
, id_distraction INT
, id_assessment INT
, id_distraction_type INT
, id_intensity_level_emotional INT
, id_intensity_level_scent INT
, id_intensity_level_sight INT
, id_intensity_level_sound INT
, id_intensity_level_touch INT
, quantity INT
, proximity_metres FLOAT
, notes TEXT
, active BIT
, is_new BIT
, name_error VARCHAR(250)
);
CREATE TEMPORARY TABLE tmp_Distraction_Copy (
id_temp INT
, id_distraction INT
, id_assessment INT
, id_distraction_type INT
, id_intensity_level_emotional INT
, id_intensity_level_scent INT
, id_intensity_level_sight INT
, id_intensity_level_sound INT
, id_intensity_level_touch INT
, quantity INT
, proximity_metres FLOAT
, notes TEXT
, active BIT
, is_new BIT
, name_error VARCHAR(250)
);
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_Msg_Error (
id_error INT NOT NULL PRIMARY KEY AUTO_INCREMENT
, id_type INT NULL
, code VARCHAR(250)
, msg TEXT NOT NULL
);
-- Get data from Temp table
INSERT INTO tmp_Distraction (
id_temp
, id_distraction
, id_assessment
, id_distraction_type
, id_intensity_level_emotional
, id_intensity_level_scent
, id_intensity_level_sight
, id_intensity_level_sound
, id_intensity_level_touch
, quantity
, proximity_metres
, notes
, active
, is_new
)
SELECT
DISTRACTION_T.id_temp
, DISTRACTION_T.id_distraction
, COALESCE(
DISTRACTION_T.id_assessment
, DISTRACTION.id_assessment
) AS id_assessment
, COALESCE(
DISTRACTION_T.id_distraction_type
, DISTRACTION.id_distraction_type
) AS id_distraction_type
, COALESCE(
DISTRACTION_T.id_intensity_level_emotional
, DISTRACTION.id_intensity_level_emotional
) AS id_intensity_level_emotional
, COALESCE(
DISTRACTION_T.id_intensity_level_scent
, DISTRACTION.id_intensity_level_scent
) AS id_intensity_level_scent
, COALESCE(
DISTRACTION_T.id_intensity_level_sight
, DISTRACTION.id_intensity_level_sight
) AS id_intensity_level_sight
, COALESCE(
DISTRACTION_T.id_intensity_level_sound
, DISTRACTION.id_intensity_level_sound
) AS id_intensity_level_sound
, COALESCE(
DISTRACTION_T.id_intensity_level_touch
, DISTRACTION.id_intensity_level_touch
) AS id_intensity_level_touch
, DISTRACTION_T.quantity
, DISTRACTION_T.proximity_metres
, DISTRACTION_T.notes
, COALESCE(DISTRACTION_T.active, 1) AS active
, CASE WHEN COALESCE(DISTRACTION_T.id_distraction, 0) < 1 THEN 1 ELSE 0 END AS is_new
FROM parts.DOG_Distraction_Temp DISTRACTION_T
LEFT JOIN parts.DOG_Distraction DISTRACTION ON DISTRACTION_T.id_distraction = DISTRACTION.id_distraction
WHERE DISTRACTION_T.guid = a_guid
;
IF a_debug = 1 THEN
SELECT 'Distraction_Temp records';
SELECT * FROM tmp_Distraction;
SELECT COUNT(*) FROM tmp_Distraction;
END IF;
-- Error names
UPDATE tmp_Distraction t_DISTRACTION
LEFT JOIN parts.DOG_Distraction_Type DISTRACTION_TYPE ON t_DISTRACTION.id_distraction_type = DISTRACTION_TYPE.id_type
LEFT JOIN parts.DOG_Distraction_Intensity_Level DISTRACTION_INTENSITY_LEVEL_EMOTIONAL ON t_DISTRACTION.id_intensity_level_emotional = DISTRACTION_INTENSITY_LEVEL_EMOTIONAL.id_intensity_level
LEFT JOIN parts.DOG_Distraction_Intensity_Level DISTRACTION_INTENSITY_LEVEL_SCENT ON t_DISTRACTION.id_intensity_level_scent = DISTRACTION_INTENSITY_LEVEL_SCENT.id_intensity_level
LEFT JOIN parts.DOG_Distraction_Intensity_Level DISTRACTION_INTENSITY_LEVEL_SIGHT ON t_DISTRACTION.id_intensity_level_sight = DISTRACTION_INTENSITY_LEVEL_SIGHT.id_intensity_level
LEFT JOIN parts.DOG_Distraction_Intensity_Level DISTRACTION_INTENSITY_LEVEL_SOUND ON t_DISTRACTION.id_intensity_level_sound = DISTRACTION_INTENSITY_LEVEL_SOUND.id_intensity_level
LEFT JOIN parts.DOG_Distraction_Intensity_Level DISTRACTION_INTENSITY_LEVEL_TOUCH ON t_DISTRACTION.id_intensity_level_touch = DISTRACTION_INTENSITY_LEVEL_TOUCH.id_intensity_level
SET t_DISTRACTION.name_error = CONCAT(
/*
CONVERT(COALESCE(t_DISTRACTION.created_on, DISTRACTION.created_on, v_time_start), CHAR)
, CASE WHEN t_DISTRACTION.notes IS NOT NULL THEN CONCAT(' - ', t_DISTRACTION.notes) ELSE '' END
*/
COALESCE(DISTRACTION_TYPE.name, '(No Distraction Type)')
, ' - '
, COALESCE(DISTRACTION_INTENSITY_LEVEL_EMOTIONAL.name, '(No Distraction Intensity Level Emotional)')
, ' - '
, COALESCE(DISTRACTION_INTENSITY_LEVEL_SCENT.name, '(No Distraction Intensity Level Scent)')
, ' - '
, COALESCE(DISTRACTION_INTENSITY_LEVEL_SCENT.name, '(No Distraction Intensity Level Sight)')
, ' - '
, COALESCE(DISTRACTION_INTENSITY_LEVEL_SCENT.name, '(No Distraction Intensity Level Sound)')
, ' - '
, COALESCE(DISTRACTION_INTENSITY_LEVEL_SCENT.name, '(No Distraction Intensity Level Touch)')
, ' - x'
, CONVERT(COALESCE(t_ASSESSMENT.quantity, 0), CHAR)
)
;
IF a_debug = 1 THEN
SELECT 'After set name_error';
SELECT * FROM tmp_Distraction;
SELECT COUNT(*) FROM tmp_Distraction;
END IF;
-- Validation
-- Missing mandatory fields
-- id_assessment
IF EXISTS (
SELECT *
FROM tmp_Distraction t_DISTRACTION
LEFT JOIN demo.DOG_Assessment ASSESSMENT ON t_DISTRACTION.id_assessment = ASSESSMENT.id_assessment
WHERE
ISNULL(t_DISTRACTION.id_assessment)
OR ISNULL(ASSESSMENT.id_assessment)
OR ASSESSMENT.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Dog Assessment Distraction(s) do not have a valid Assessment: ', GROUP_CONCAT(t_DISTRACTION.name_error SEPARATOR ', ')) AS msg
FROM tmp_Distraction t_DISTRACTION
LEFT JOIN parts.DOG_Assessment ASSESSMENT ON t_DISTRACTION.id_assessment = ASSESSMENT.id_assessment
WHERE
ISNULL(t_DISTRACTION.id_assessment)
OR ISNULL(ASSESSMENT.id_assessment)
OR ASSESSMENT.active = 0
;
END IF;
-- id_distraction_type
IF EXISTS (
SELECT *
FROM tmp_Distraction t_DISTRACTION
LEFT JOIN demo.DOG_Distraction_Type DISTRACTION_TYPE ON t_DISTRACTION.id_distraction_type = DISTRACTION_TYPE.id_distraction_type
WHERE
ISNULL(t_DISTRACTION.id_distraction_type)
OR ISNULL(DISTRACTION_TYPE.id_distraction_type)
OR DISTRACTION_TYPE.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Dog Distraction_Type Distraction(s) do not have a valid Distraction_Type: ', GROUP_CONCAT(t_DISTRACTION.name_error SEPARATOR ', ')) AS msg
FROM tmp_Distraction t_DISTRACTION
LEFT JOIN parts.DOG_Distraction_Type DISTRACTION_TYPE ON t_DISTRACTION.id_distraction_type = DISTRACTION_TYPE.id_distraction_type
WHERE
ISNULL(t_DISTRACTION.id_distraction_type)
OR ISNULL(DISTRACTION_TYPE.id_distraction_type)
OR DISTRACTION_TYPE.active = 0
;
END IF;
-- id_intensity_level_emotional
IF EXISTS (
SELECT *
FROM tmp_Distraction t_DISTRACTION
LEFT JOIN demo.DOG_Distraction_Intensity_Level DISTRACTION_INTENSITY_LEVEL_EMOTIONAL ON t_DISTRACTION.id_intensity_level_emotional = DISTRACTION_INTENSITY_LEVEL_EMOTIONAL.id_intensity_level_emotional
WHERE
ISNULL(t_DISTRACTION.id_intensity_level_emotional)
OR ISNULL(DISTRACTION_INTENSITY_LEVEL_EMOTIONAL.id_intensity_level_emotional)
OR DISTRACTION_INTENSITY_LEVEL_EMOTIONAL.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Distraction(s) do not have a valid Distraction_Intensity_Level_Emotional: ', GROUP_CONCAT(t_DISTRACTION.name_error SEPARATOR ', ')) AS msg
FROM tmp_Distraction t_DISTRACTION
LEFT JOIN parts.DOG_Distraction_Intensity_Level DISTRACTION_INTENSITY_LEVEL_EMOTIONAL ON t_DISTRACTION.id_intensity_level_emotional = DISTRACTION_INTENSITY_LEVEL_EMOTIONAL.id_intensity_level_emotional
WHERE
ISNULL(t_DISTRACTION.id_intensity_level_emotional)
OR ISNULL(DISTRACTION_INTENSITY_LEVEL_EMOTIONAL.id_intensity_level_emotional)
OR DISTRACTION_INTENSITY_LEVEL_EMOTIONAL.active = 0
;
END IF;
-- id_intensity_level_scent
IF EXISTS (
SELECT *
FROM tmp_Distraction t_DISTRACTION
LEFT JOIN demo.DOG_Distraction_Intensity_Level DISTRACTION_INTENSITY_LEVEL_SCENT ON t_DISTRACTION.id_intensity_level_scent = DISTRACTION_INTENSITY_LEVEL_SCENT.id_intensity_level
WHERE
ISNULL(t_DISTRACTION.id_intensity_level_scent)
OR ISNULL(DISTRACTION_INTENSITY_LEVEL_SCENT.id_intensity_level_scent)
OR DISTRACTION_INTENSITY_LEVEL_SCENT.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Distraction(s) do not have a valid Intensity Level Scent: ', GROUP_CONCAT(t_DISTRACTION.name_error SEPARATOR ', ')) AS msg
FROM tmp_Distraction t_DISTRACTION
LEFT JOIN parts.DOG_Distraction_Intensity_Level DISTRACTION_INTENSITY_LEVEL_SCENT ON t_DISTRACTION.id_intensity_level_scent = DISTRACTION_INTENSITY_LEVEL_SCENT.id_intensity_level
WHERE
ISNULL(t_DISTRACTION.id_intensity_level_scent)
OR ISNULL(DISTRACTION_INTENSITY_LEVEL_SCENT.id_intensity_level_scent)
OR DISTRACTION_INTENSITY_LEVEL_SCENT.active = 0
;
END IF;
-- id_intensity_level_sight
IF EXISTS (
SELECT *
FROM tmp_Distraction t_DISTRACTION
LEFT JOIN demo.DOG_Distraction_Intensity_Level DISTRACTION_INTENSITY_LEVEL_SIGHT ON t_DISTRACTION.id_intensity_level_sight = DISTRACTION_INTENSITY_LEVEL_SIGHT.id_intensity_level
WHERE
ISNULL(t_DISTRACTION.id_intensity_level_sight)
OR ISNULL(DISTRACTION_INTENSITY_LEVEL_SIGHT.id_intensity_level_sight)
OR DISTRACTION_INTENSITY_LEVEL_SIGHT.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Distraction(s) do not have a valid Intensity Level Sight: ', GROUP_CONCAT(t_DISTRACTION.name_error SEPARATOR ', ')) AS msg
FROM tmp_Distraction t_DISTRACTION
LEFT JOIN parts.DOG_Distraction_Intensity_Level DISTRACTION_INTENSITY_LEVEL_SIGHT ON t_DISTRACTION.id_intensity_level_sight = DISTRACTION_INTENSITY_LEVEL_SIGHT.id_intensity_level
WHERE
ISNULL(t_DISTRACTION.id_intensity_level_sight)
OR ISNULL(DISTRACTION_INTENSITY_LEVEL_SIGHT.id_intensity_level_sight)
OR DISTRACTION_INTENSITY_LEVEL_SIGHT.active = 0
;
END IF;
-- id_intensity_level_sound
IF EXISTS (
SELECT *
FROM tmp_Distraction t_DISTRACTION
LEFT JOIN demo.DOG_Distraction_Intensity_Level DISTRACTION_INTENSITY_LEVEL_SOUND ON t_DISTRACTION.id_intensity_level_sound = DISTRACTION_INTENSITY_LEVEL_SOUND.id_intensity_level
WHERE
ISNULL(t_DISTRACTION.id_intensity_level_sound)
OR ISNULL(DISTRACTION_INTENSITY_LEVEL_SOUND.id_intensity_level_sound)
OR DISTRACTION_INTENSITY_LEVEL_SOUND.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Distraction(s) do not have a valid Intensity Level Sound: ', GROUP_CONCAT(t_DISTRACTION.name_error SEPARATOR ', ')) AS msg
FROM tmp_Distraction t_DISTRACTION
LEFT JOIN parts.DOG_Distraction_Intensity_Level DISTRACTION_INTENSITY_LEVEL_SOUND ON t_DISTRACTION.id_intensity_level_sound = DISTRACTION_INTENSITY_LEVEL_SOUND.id_intensity_level
WHERE
ISNULL(t_DISTRACTION.id_intensity_level_sound)
OR ISNULL(DISTRACTION_INTENSITY_LEVEL_SOUND.id_intensity_level_sound)
OR DISTRACTION_INTENSITY_LEVEL_SOUND.active = 0
;
END IF;
-- id_intensity_level_touch
IF EXISTS (
SELECT *
FROM tmp_Distraction t_DISTRACTION
LEFT JOIN demo.DOG_Distraction_Intensity_Level DISTRACTION_INTENSITY_LEVEL_TOUCH ON t_DISTRACTION.id_intensity_level_touch = DISTRACTION_INTENSITY_LEVEL_TOUCH.id_intensity_level
WHERE
ISNULL(t_DISTRACTION.id_intensity_level_touch)
OR ISNULL(DISTRACTION_INTENSITY_LEVEL_TOUCH.id_intensity_level_touch)
OR DISTRACTION_INTENSITY_LEVEL_TOUCH.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Distraction(s) do not have a valid Intensity Level Touch: ', GROUP_CONCAT(t_DISTRACTION.name_error SEPARATOR ', ')) AS msg
FROM tmp_Distraction t_DISTRACTION
LEFT JOIN parts.DOG_Distraction_Intensity_Level DISTRACTION_INTENSITY_LEVEL_TOUCH ON t_DISTRACTION.id_intensity_level_touch = DISTRACTION_INTENSITY_LEVEL_TOUCH.id_intensity_level
WHERE
ISNULL(t_DISTRACTION.id_intensity_level_touch)
OR ISNULL(DISTRACTION_INTENSITY_LEVEL_TOUCH.id_intensity_level_touch)
OR DISTRACTION_INTENSITY_LEVEL_TOUCH.active = 0
;
END IF;
-- Permissions
-- Can Create
CALL parts.p_dog_calc_user(
a_guid
, 0 -- get_all_user
, 0 -- get_inactive_user
, a_id_user -- ids_user
, '' -- a_auth0_ids_user
, '' -- a_names_user
, '' -- a_emails_user
, 1 -- a_require_all_id_search_filters_met
, 1 -- a_require_any_id_search_filters_met
, 0 -- a_require_all_non_id_search_filters_met
, 0 -- a_require_any_non_id_search_filters_met
, v_id_permission_dog_new -- ids_permission
, v_id_access_level_edit -- ids_access_level
, 0 -- a_show_errors
, 0 -- a_debug
);
SELECT
IFNULL(CU_T.has_access, 0)
INTO
v_can_create
FROM parts.DOG_Calc_User_Temp CU_T
WHERE CU_T.GUID = a_guid
LIMIT 1
;
CALL parts.p_dog_clear_calc_user(
a_guid
, 0 -- a_debug
);
IF v_can_create = 0 THEN
DELETE t_ME
FROM tmp_Msg_Error t_ME
WHERE t_ME.id_type <> v_id_type_error_no_permission
;
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
VALUES (
v_id_type_error_no_permission
, v_code_type_error_no_permission
, 'You do not have permission to edit Distractions.'
)
;
END IF;
IF EXISTS (SELECT * FROM tmp_Msg_Error t_ERROR INNER JOIN parts.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type WHERE ERROR_TYPE.is_breaking_error = 1 LIMIT 1) THEN
IF a_debug = 1 THEN
SELECT * from tmp_Distraction;
END IF;
DELETE FROM tmp_Distraction;
END IF;
IF NOT EXISTS (SELECT * FROM tmp_Msg_Error t_ERROR INNER JOIN parts.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type WHERE ERROR_TYPE.is_breaking_error = 1 LIMIT 1) THEN
START TRANSACTION;
INSERT INTO parts.DOG_Dog_Change_Set (
comment
, id_user_updated_last_by
, updated_last_on
)
VALUES (
a_comment
, a_id_user
, v_time_start
)
;
SET v_id_change_set := LAST_INSERT_ID();
UPDATE parts.DOG_Distraction DISTRACTION
INNER JOIN tmp_Distraction t_DISTRACTION
ON DISTRACTION.id_distraction = t_DISTRACTION.id_distraction
AND t_DISTRACTION.is_new = 0
SET
DISTRACTION.id_assessment = t_DISTRACTION.id_assessment
, DISTRACTION.id_distraction_type = t_DISTRACTION.id_distraction_type
, DISTRACTION.id_intensity_level_emotional = t_DISTRACTION.id_intensity_level_emotional
, DISTRACTION.id_intensity_level_scent = t_DISTRACTION.id_intensity_level_scent
, DISTRACTION.id_intensity_level_sight = t_DISTRACTION.id_intensity_level_sight
, DISTRACTION.id_intensity_level_sound = t_DISTRACTION.id_intensity_level_sound
, DISTRACTION.id_intensity_level_touch = t_DISTRACTION.id_intensity_level_touch
, DISTRACTION.quantity = t_DISTRACTION.quantity
, DISTRACTION.proximity_metres = t_DISTRACTION.proximity_metres
, DISTRACTION.notes = t_DISTRACTION.notes
, DISTRACTION.active = t_DISTRACTION.active
, DISTRACTION.id_change_set = v_id_change_set
;
INSERT INTO parts.DOG_Distraction (
id_assessment
, id_distraction_type
, id_intensity_level_emotional
, id_intensity_level_scent
, id_intensity_level_sight
, id_intensity_level_sound
, id_intensity_level_touch
, quantity
, proximity_metres
, notes
, active
, id_user_created_by
, created_on
)
SELECT
t_DISTRACTION.id_assessment AS id_assessment
, t_DISTRACTION.id_distraction_type AS id_distraction_type
, t_DISTRACTION.id_intensity_level_emotional AS id_intensity_level_emotional
, t_DISTRACTION.id_intensity_level_scent AS id_intensity_level_scent
, t_DISTRACTION.id_intensity_level_sight AS id_intensity_level_sight
, t_DISTRACTION.id_intensity_level_sound AS id_intensity_level_sound
, t_DISTRACTION.id_intensity_level_touch AS id_intensity_level_touch
, t_DISTRACTION.quantity AS quantity
, t_DISTRACTION.proximity_metres AS proximity_metres
, t_DISTRACTION.notes AS notes
, t_DISTRACTION.active AS active
, a_id_user AS created_by
, v_time_start AS created_on
FROM tmp_Distraction t_DISTRACTION
WHERE
t_DISTRACTION.is_new = 1
AND t_DISTRACTION.active = 1
;
COMMIT;
END IF;
START TRANSACTION;
DELETE FROM parts.DOG_Distraction_Temp
WHERE GUID = a_guid
;
COMMIT;
-- Errors
SELECT
t_ERROR.id_error
, t_ERROR.id_type
, t_ERROR.code
, ERROR_TYPE.name
, ERROR_TYPE.description
, ERROR_TYPE.is_breaking_error
, ERROR_TYPE.background_colour
, ERROR_TYPE.text_colour
, t_ERROR.msg
FROM tmp_Msg_Error t_ERROR
INNER JOIN parts.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type
;
IF a_debug = 1 THEN
SELECT * FROM tmp_Distraction;
END IF;
DROP TEMPORARY TABLE tmp_Distraction;
DROP TEMPORARY TABLE tmp_Msg_Error;
IF a_debug = 1 THEN
CALL parts.p_core_debug_timing_reporting ( v_time_start );
END IF;
END //
DELIMITER ;
/*
'ripplesipplenippletippledipplekipple'
DELETE FROM parts.DOG_Distraction WHERE id_distraction > 740;
* /
delete
from parts.DOG_Distraction_Audit
where id_distraction > 768
;
delete
from parts.DOG_Distraction
where id_distraction > 768
;
delete
from parts.DOG_Distraction_Temp
;
select
*
-- COUNT(*)
-- delete
from parts.DOG_Distraction_Temp
;
select COUNT(*)
from parts.DOG_Distraction_Temp
;
select
*
-- COUNT(*)
-- delete
from parts.DOG_Distraction
;
select COUNT(*)
from parts.DOG_Distraction
;
INSERT INTO parts.DOG_Distraction_Temp (
id_distraction
, id_dog
, id_command
, hand_signal_description
, notes
, active
, guid
)
VALUES (
-1 -- id_distraction
, 1 -- id_dog
, 1 -- id_command
, 'Test deez noots' -- hand_signal_description
, NULL -- notes
, 1 -- active
, 'ripplesipplenippletippledipplekipple'
);
CALL parts.p_dog_save_distraction (
'nipples'
, 'ripplesipplenippletippledipplekipple'
, 1
, 1
);
select
*
-- COUNT(*)
-- delete
from parts.DOG_Distraction_Temp
;
select COUNT(*)
from parts.DOG_Distraction_Temp
;
select
*
-- COUNT(*)
-- delete
from parts.DOG_Distraction
;
select COUNT(*)
from parts.DOG_Distraction
;
*/

View File

@@ -0,0 +1,672 @@
USE parts;
DROP PROCEDURE IF EXISTS parts.p_dog_save_assessment_command_modality_link;
DELIMITER //
CREATE PROCEDURE parts.p_dog_save_assessment_command_modality_link (
IN a_comment VARCHAR(500),
IN a_guid BINARY(36),
IN a_id_user INT,
IN a_debug BIT
)
BEGIN
DECLARE v_can_admin BIT;
DECLARE v_can_create BIT;
DECLARE v_code_type_error_bad_data VARCHAR(100);
DECLARE v_id_access_level_edit INT;
DECLARE v_id_change_set INT;
DECLARE v_id_permission_dog_new INT;
DECLARE v_id_type_error_bad_data INT;
DECLARE v_time_start TIMESTAMP(6);
DECLARE exit handler for SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
@sqlstate = RETURNED_SQLSTATE
, @errno = MYSQL_ERRNO
, @text = MESSAGE_TEXT
;
ROLLBACK;
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_Msg_Error (
id_error INT NOT NULL PRIMARY KEY AUTO_INCREMENT
, id_type INT NULL
, code VARCHAR(250)
, msg TEXT NOT NULL
);
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
MET.id_type
, @errno
, @text
FROM parts.CORE_Msg_Error_Type MET
WHERE MET.code = 'MYSQL_ERROR'
;
SELECT
t_ERROR.id_error
, t_ERROR.id_type
, t_ERROR.code
, ERROR_TYPE.name
, ERROR_TYPE.description
, ERROR_TYPE.is_breaking_error
, ERROR_TYPE.background_colour
, ERROR_TYPE.text_colour
, t_ERROR.msg
FROM tmp_Msg_Error t_ERROR
INNER JOIN parts.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type
;
DROP TABLE IF EXISTS tmp_Msg_Error;
END;
SET SESSION group_concat_max_len=15000;
SET v_time_start := CURRENT_TIMESTAMP(6);
SET v_code_type_error_bad_data := 'BAD_DATA';
SET v_id_type_error_bad_data := (SELECT ERROR_TYPE.id_type FROM parts.CORE_Msg_Error_Type ERROR_TYPE WHERE ERROR_TYPE.code = v_code_type_error_bad_data LIMIT 1);
SET v_id_permission_dog_new := (SELECT PERMISSION.id_permission FROM parts.DOG_Permission PERMISSION WHERE PERMISSION.code = 'DOG_CREATE' LIMIT 1);
SET v_id_access_level_edit := (SELECT ACCESS_LEVEL.id_access_level FROM parts.DOG_Access_Level ACCESS_LEVEL WHERE ACCESS_LEVEL.code = 'EDIT' LIMIT 1);
CALL parts.p_core_validate_guid ( a_guid );
DROP TABLE IF EXISTS tmp_Assessment_Command_Modality_Link_Copy;
DROP TABLE IF EXISTS tmp_Assessment_Command_Modality_Link;
CREATE TEMPORARY TABLE tmp_Assessment_Command_Modality_Link (
id_temp INT
, id_link INT
, id_assessment INT
, id_command INT
, id_command_modality INT
, id_bribe INT
, distance_from_handler FLOAT
, is_in_sight_of_handler BIT
, is_in_scent_range_of_handler BIT
, is_in_hearing_range_of_handler BIT
, is_on_lead BIT
, trial_count INT
, active BIT
, is_new BIT
, name_error VARCHAR(250)
);
CREATE TEMPORARY TABLE tmp_Assessment_Command_Modality_Link_Copy (
id_temp INT
, id_link INT
, id_assessment INT
, id_command INT
, id_command_modality INT
, id_bribe INT
, id_distance_from_handler INT
, id_is_in_sight_of_handler INT
, id_is_in_scent_range_of_handler INT
, is_in_hearing_range_of_handler INT
, is_on_lead FLOAT
, trial_count TEXT
, active BIT
, is_new BIT
, name_error VARCHAR(250)
);
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_Msg_Error (
id_error INT NOT NULL PRIMARY KEY AUTO_INCREMENT
, id_type INT NULL
, code VARCHAR(250)
, msg TEXT NOT NULL
);
-- Get data from Temp table
INSERT INTO tmp_Assessment_Command_Modality_Link (
id_temp
, id_link
, id_assessment
, id_command
, id_command_modality
, id_bribe
, id_distance_from_handler
, id_is_in_sight_of_handler
, id_is_in_scent_range_of_handler
, is_in_hearing_range_of_handler
, is_on_lead
, trial_count
, active
, is_new
)
SELECT
ASSESSMENT_COMMAND_MODALITY_LINK_T.id_temp
, ASSESSMENT_COMMAND_MODALITY_LINK_T.id_link
, COALESCE(
ASSESSMENT_COMMAND_MODALITY_LINK_T.id_assessment
, ASSESSMENT_COMMAND_MODALITY_LINK.id_assessment
) AS id_assessment
, COALESCE(
ASSESSMENT_COMMAND_MODALITY_LINK_T.id_command
, ASSESSMENT_COMMAND_MODALITY_LINK.id_command
) AS id_command
, COALESCE(
ASSESSMENT_COMMAND_MODALITY_LINK_T.id_command_modality
, ASSESSMENT_COMMAND_MODALITY_LINK.id_command_modality
) AS id_command_modality
, COALESCE(
ASSESSMENT_COMMAND_MODALITY_LINK_T.id_bribe
, ASSESSMENT_COMMAND_MODALITY_LINK.id_bribe
) AS id_bribe
, COALESCE(
ASSESSMENT_COMMAND_MODALITY_LINK_T.id_distance_from_handler
, ASSESSMENT_COMMAND_MODALITY_LINK.id_distance_from_handler
) AS id_distance_from_handler
, COALESCE(
ASSESSMENT_COMMAND_MODALITY_LINK_T.id_is_in_sight_of_handler
, ASSESSMENT_COMMAND_MODALITY_LINK.id_is_in_sight_of_handler
) AS id_is_in_sight_of_handler
, COALESCE(
ASSESSMENT_COMMAND_MODALITY_LINK_T.id_is_in_scent_range_of_handler
, ASSESSMENT_COMMAND_MODALITY_LINK.id_is_in_scent_range_of_handler
) AS id_is_in_scent_range_of_handler
, ASSESSMENT_COMMAND_MODALITY_LINK_T.is_in_hearing_range_of_handler
, ASSESSMENT_COMMAND_MODALITY_LINK_T.is_on_lead
, ASSESSMENT_COMMAND_MODALITY_LINK_T.trial_count
, COALESCE(ASSESSMENT_COMMAND_MODALITY_LINK_T.active, 1) AS active
, CASE WHEN COALESCE(ASSESSMENT_COMMAND_MODALITY_LINK_T.id_link, 0) < 1 THEN 1 ELSE 0 END AS is_new
FROM parts.DOG_Assessment_Command_Modality_Link_Temp ASSESSMENT_COMMAND_MODALITY_LINK_T
LEFT JOIN parts.DOG_Assessment_Command_Modality_Link ASSESSMENT_COMMAND_MODALITY_LINK ON ASSESSMENT_COMMAND_MODALITY_LINK_T.id_link = ASSESSMENT_COMMAND_MODALITY_LINK.id_link
WHERE ASSESSMENT_COMMAND_MODALITY_LINK_T.guid = a_guid
;
IF a_debug = 1 THEN
SELECT 'Assessment_Command_Modality_Link_Temp records';
SELECT * FROM tmp_Assessment_Command_Modality_Link;
SELECT COUNT(*) FROM tmp_Assessment_Command_Modality_Link;
END IF;
-- Error names
UPDATE tmp_Assessment_Command_Modality_Link t_ASSESSMENT_COMMAND_MODALITY_LINK
LEFT JOIN parts.DOG_Assessment_Command_Modality_Command ASSESSMENT_COMMAND_MODALITY_COMMAND ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_command = ASSESSMENT_COMMAND_MODALITY_COMMAND.id_type
LEFT JOIN parts.DOG_Assessment_Command_Modality_Link_Intensity_Level ASSESSMENT_COMMAND_MODALITY_LINK_COMMAND_MODALITY ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_command_modality = ASSESSMENT_COMMAND_MODALITY_LINK_COMMAND_MODALITY.id_intensity_level
LEFT JOIN parts.DOG_Assessment_Command_Modality_Link_Intensity_Level ASSESSMENT_COMMAND_MODALITY_LINK_BRIBE ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_bribe = ASSESSMENT_COMMAND_MODALITY_LINK_BRIBE.id_intensity_level
LEFT JOIN parts.DOG_Assessment_Command_Modality_Link_Intensity_Level ASSESSMENT_COMMAND_MODALITY_LINK_DISTANCE_FROM_HANDLER ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_distance_from_handler = ASSESSMENT_COMMAND_MODALITY_LINK_DISTANCE_FROM_HANDLER.id_intensity_level
LEFT JOIN parts.DOG_Assessment_Command_Modality_Link_Intensity_Level ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SIGHT_OF_HANDLER ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_is_in_sight_of_handler = ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SIGHT_OF_HANDLER.id_intensity_level
LEFT JOIN parts.DOG_Assessment_Command_Modality_Link_Intensity_Level ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SCENT_RANGE_OF_HANDLER ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_is_in_scent_range_of_handler = ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SCENT_RANGE_OF_HANDLER.id_intensity_level
SET t_ASSESSMENT_COMMAND_MODALITY_LINK.name_error = CONCAT(
/*
CONVERT(COALESCE(t_ASSESSMENT_COMMAND_MODALITY_LINK.created_on, ASSESSMENT_COMMAND_MODALITY_LINK.created_on, v_time_start), CHAR)
, CASE WHEN t_ASSESSMENT_COMMAND_MODALITY_LINK.trial_count IS NOT NULL THEN CONCAT(' - ', t_ASSESSMENT_COMMAND_MODALITY_LINK.trial_count) ELSE '' END
*/
COALESCE(ASSESSMENT_COMMAND_MODALITY_COMMAND.name, '(No Assessment_Command_Modality_Link Type)')
, ' - '
, COALESCE(ASSESSMENT_COMMAND_MODALITY_LINK_COMMAND_MODALITY.name, '(No Assessment_Command_Modality_Link Intensity Level Emotional)')
, ' - '
, COALESCE(ASSESSMENT_COMMAND_MODALITY_LINK_BRIBE.name, '(No Assessment_Command_Modality_Link Intensity Level Scent)')
, ' - '
, COALESCE(ASSESSMENT_COMMAND_MODALITY_LINK_BRIBE.name, '(No Assessment_Command_Modality_Link Intensity Level Sight)')
, ' - '
, COALESCE(ASSESSMENT_COMMAND_MODALITY_LINK_BRIBE.name, '(No Assessment_Command_Modality_Link Intensity Level Sound)')
, ' - '
, COALESCE(ASSESSMENT_COMMAND_MODALITY_LINK_BRIBE.name, '(No Assessment_Command_Modality_Link Intensity Level Touch)')
, ' - x'
, CONVERT(COALESCE(t_ASSESSMENT.is_in_hearing_range_of_handler, 0), CHAR)
)
;
IF a_debug = 1 THEN
SELECT 'After set name_error';
SELECT * FROM tmp_Assessment_Command_Modality_Link;
SELECT COUNT(*) FROM tmp_Assessment_Command_Modality_Link;
END IF;
-- Validation
-- Missing mandatory fields
-- id_assessment
IF EXISTS (
SELECT *
FROM tmp_Assessment_Command_Modality_Link t_ASSESSMENT_COMMAND_MODALITY_LINK
LEFT JOIN demo.DOG_Assessment ASSESSMENT ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_assessment = ASSESSMENT.id_assessment
WHERE
ISNULL(t_ASSESSMENT_COMMAND_MODALITY_LINK.id_assessment)
OR ISNULL(ASSESSMENT.id_assessment)
OR ASSESSMENT.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Dog Assessment Assessment_Command_Modality_Link(s) do not have a valid Assessment: ', GROUP_CONCAT(t_ASSESSMENT_COMMAND_MODALITY_LINK.name_error SEPARATOR ', ')) AS msg
FROM tmp_Assessment_Command_Modality_Link t_ASSESSMENT_COMMAND_MODALITY_LINK
LEFT JOIN parts.DOG_Assessment ASSESSMENT ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_assessment = ASSESSMENT.id_assessment
WHERE
ISNULL(t_ASSESSMENT_COMMAND_MODALITY_LINK.id_assessment)
OR ISNULL(ASSESSMENT.id_assessment)
OR ASSESSMENT.active = 0
;
END IF;
-- id_command
IF EXISTS (
SELECT *
FROM tmp_Assessment_Command_Modality_Link t_ASSESSMENT_COMMAND_MODALITY_LINK
LEFT JOIN demo.DOG_Assessment_Command_Modality_Command ASSESSMENT_COMMAND_MODALITY_COMMAND ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_command = ASSESSMENT_COMMAND_MODALITY_COMMAND.id_command
WHERE
ISNULL(t_ASSESSMENT_COMMAND_MODALITY_LINK.id_command)
OR ISNULL(ASSESSMENT_COMMAND_MODALITY_COMMAND.id_command)
OR ASSESSMENT_COMMAND_MODALITY_COMMAND.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Dog Assessment_Command_Modality_Command Assessment_Command_Modality_Link(s) do not have a valid Assessment_Command_Modality_Command: ', GROUP_CONCAT(t_ASSESSMENT_COMMAND_MODALITY_LINK.name_error SEPARATOR ', ')) AS msg
FROM tmp_Assessment_Command_Modality_Link t_ASSESSMENT_COMMAND_MODALITY_LINK
LEFT JOIN parts.DOG_Assessment_Command_Modality_Command ASSESSMENT_COMMAND_MODALITY_COMMAND ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_command = ASSESSMENT_COMMAND_MODALITY_COMMAND.id_command
WHERE
ISNULL(t_ASSESSMENT_COMMAND_MODALITY_LINK.id_command)
OR ISNULL(ASSESSMENT_COMMAND_MODALITY_COMMAND.id_command)
OR ASSESSMENT_COMMAND_MODALITY_COMMAND.active = 0
;
END IF;
-- id_command_modality
IF EXISTS (
SELECT *
FROM tmp_Assessment_Command_Modality_Link t_ASSESSMENT_COMMAND_MODALITY_LINK
LEFT JOIN demo.DOG_Assessment_Command_Modality_Link_Intensity_Level ASSESSMENT_COMMAND_MODALITY_LINK_COMMAND_MODALITY ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_command_modality = ASSESSMENT_COMMAND_MODALITY_LINK_COMMAND_MODALITY.id_command_modality
WHERE
ISNULL(t_ASSESSMENT_COMMAND_MODALITY_LINK.id_command_modality)
OR ISNULL(ASSESSMENT_COMMAND_MODALITY_LINK_COMMAND_MODALITY.id_command_modality)
OR ASSESSMENT_COMMAND_MODALITY_LINK_COMMAND_MODALITY.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Assessment_Command_Modality_Link(s) do not have a valid Assessment_Command_Modality_Link_Command_Modality: ', GROUP_CONCAT(t_ASSESSMENT_COMMAND_MODALITY_LINK.name_error SEPARATOR ', ')) AS msg
FROM tmp_Assessment_Command_Modality_Link t_ASSESSMENT_COMMAND_MODALITY_LINK
LEFT JOIN parts.DOG_Assessment_Command_Modality_Link_Intensity_Level ASSESSMENT_COMMAND_MODALITY_LINK_COMMAND_MODALITY ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_command_modality = ASSESSMENT_COMMAND_MODALITY_LINK_COMMAND_MODALITY.id_command_modality
WHERE
ISNULL(t_ASSESSMENT_COMMAND_MODALITY_LINK.id_command_modality)
OR ISNULL(ASSESSMENT_COMMAND_MODALITY_LINK_COMMAND_MODALITY.id_command_modality)
OR ASSESSMENT_COMMAND_MODALITY_LINK_COMMAND_MODALITY.active = 0
;
END IF;
-- id_bribe
IF EXISTS (
SELECT *
FROM tmp_Assessment_Command_Modality_Link t_ASSESSMENT_COMMAND_MODALITY_LINK
LEFT JOIN demo.DOG_Assessment_Command_Modality_Link_Intensity_Level ASSESSMENT_COMMAND_MODALITY_LINK_BRIBE ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_bribe = ASSESSMENT_COMMAND_MODALITY_LINK_BRIBE.id_intensity_level
WHERE
ISNULL(t_ASSESSMENT_COMMAND_MODALITY_LINK.id_bribe)
OR ISNULL(ASSESSMENT_COMMAND_MODALITY_LINK_BRIBE.id_bribe)
OR ASSESSMENT_COMMAND_MODALITY_LINK_BRIBE.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Assessment_Command_Modality_Link(s) do not have a valid Intensity Level Scent: ', GROUP_CONCAT(t_ASSESSMENT_COMMAND_MODALITY_LINK.name_error SEPARATOR ', ')) AS msg
FROM tmp_Assessment_Command_Modality_Link t_ASSESSMENT_COMMAND_MODALITY_LINK
LEFT JOIN parts.DOG_Assessment_Command_Modality_Link_Intensity_Level ASSESSMENT_COMMAND_MODALITY_LINK_BRIBE ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_bribe = ASSESSMENT_COMMAND_MODALITY_LINK_BRIBE.id_intensity_level
WHERE
ISNULL(t_ASSESSMENT_COMMAND_MODALITY_LINK.id_bribe)
OR ISNULL(ASSESSMENT_COMMAND_MODALITY_LINK_BRIBE.id_bribe)
OR ASSESSMENT_COMMAND_MODALITY_LINK_BRIBE.active = 0
;
END IF;
-- id_distance_from_handler
IF EXISTS (
SELECT *
FROM tmp_Assessment_Command_Modality_Link t_ASSESSMENT_COMMAND_MODALITY_LINK
LEFT JOIN demo.DOG_Assessment_Command_Modality_Link_Intensity_Level ASSESSMENT_COMMAND_MODALITY_LINK_DISTANCE_FROM_HANDLER ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_distance_from_handler = ASSESSMENT_COMMAND_MODALITY_LINK_DISTANCE_FROM_HANDLER.id_intensity_level
WHERE
ISNULL(t_ASSESSMENT_COMMAND_MODALITY_LINK.id_distance_from_handler)
OR ISNULL(ASSESSMENT_COMMAND_MODALITY_LINK_DISTANCE_FROM_HANDLER.id_distance_from_handler)
OR ASSESSMENT_COMMAND_MODALITY_LINK_DISTANCE_FROM_HANDLER.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Assessment_Command_Modality_Link(s) do not have a valid Intensity Level Sight: ', GROUP_CONCAT(t_ASSESSMENT_COMMAND_MODALITY_LINK.name_error SEPARATOR ', ')) AS msg
FROM tmp_Assessment_Command_Modality_Link t_ASSESSMENT_COMMAND_MODALITY_LINK
LEFT JOIN parts.DOG_Assessment_Command_Modality_Link_Intensity_Level ASSESSMENT_COMMAND_MODALITY_LINK_DISTANCE_FROM_HANDLER ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_distance_from_handler = ASSESSMENT_COMMAND_MODALITY_LINK_DISTANCE_FROM_HANDLER.id_intensity_level
WHERE
ISNULL(t_ASSESSMENT_COMMAND_MODALITY_LINK.id_distance_from_handler)
OR ISNULL(ASSESSMENT_COMMAND_MODALITY_LINK_DISTANCE_FROM_HANDLER.id_distance_from_handler)
OR ASSESSMENT_COMMAND_MODALITY_LINK_DISTANCE_FROM_HANDLER.active = 0
;
END IF;
-- id_is_in_sight_of_handler
IF EXISTS (
SELECT *
FROM tmp_Assessment_Command_Modality_Link t_ASSESSMENT_COMMAND_MODALITY_LINK
LEFT JOIN demo.DOG_Assessment_Command_Modality_Link_Intensity_Level ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SIGHT_OF_HANDLER ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_is_in_sight_of_handler = ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SIGHT_OF_HANDLER.id_intensity_level
WHERE
ISNULL(t_ASSESSMENT_COMMAND_MODALITY_LINK.id_is_in_sight_of_handler)
OR ISNULL(ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SIGHT_OF_HANDLER.id_is_in_sight_of_handler)
OR ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SIGHT_OF_HANDLER.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Assessment_Command_Modality_Link(s) do not have a valid Intensity Level Sound: ', GROUP_CONCAT(t_ASSESSMENT_COMMAND_MODALITY_LINK.name_error SEPARATOR ', ')) AS msg
FROM tmp_Assessment_Command_Modality_Link t_ASSESSMENT_COMMAND_MODALITY_LINK
LEFT JOIN parts.DOG_Assessment_Command_Modality_Link_Intensity_Level ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SIGHT_OF_HANDLER ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_is_in_sight_of_handler = ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SIGHT_OF_HANDLER.id_intensity_level
WHERE
ISNULL(t_ASSESSMENT_COMMAND_MODALITY_LINK.id_is_in_sight_of_handler)
OR ISNULL(ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SIGHT_OF_HANDLER.id_is_in_sight_of_handler)
OR ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SIGHT_OF_HANDLER.active = 0
;
END IF;
-- id_is_in_scent_range_of_handler
IF EXISTS (
SELECT *
FROM tmp_Assessment_Command_Modality_Link t_ASSESSMENT_COMMAND_MODALITY_LINK
LEFT JOIN demo.DOG_Assessment_Command_Modality_Link_Intensity_Level ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SCENT_RANGE_OF_HANDLER ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_is_in_scent_range_of_handler = ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SCENT_RANGE_OF_HANDLER.id_intensity_level
WHERE
ISNULL(t_ASSESSMENT_COMMAND_MODALITY_LINK.id_is_in_scent_range_of_handler)
OR ISNULL(ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SCENT_RANGE_OF_HANDLER.id_is_in_scent_range_of_handler)
OR ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SCENT_RANGE_OF_HANDLER.active = 0
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Assessment_Command_Modality_Link(s) do not have a valid Intensity Level Touch: ', GROUP_CONCAT(t_ASSESSMENT_COMMAND_MODALITY_LINK.name_error SEPARATOR ', ')) AS msg
FROM tmp_Assessment_Command_Modality_Link t_ASSESSMENT_COMMAND_MODALITY_LINK
LEFT JOIN parts.DOG_Assessment_Command_Modality_Link_Intensity_Level ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SCENT_RANGE_OF_HANDLER ON t_ASSESSMENT_COMMAND_MODALITY_LINK.id_is_in_scent_range_of_handler = ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SCENT_RANGE_OF_HANDLER.id_intensity_level
WHERE
ISNULL(t_ASSESSMENT_COMMAND_MODALITY_LINK.id_is_in_scent_range_of_handler)
OR ISNULL(ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SCENT_RANGE_OF_HANDLER.id_is_in_scent_range_of_handler)
OR ASSESSMENT_COMMAND_MODALITY_LINK_IS_IN_SCENT_RANGE_OF_HANDLER.active = 0
;
END IF;
-- Permissions
-- Can Create
CALL parts.p_dog_calc_user(
a_guid
, 0 -- get_all_user
, 0 -- get_inactive_user
, a_id_user -- ids_user
, '' -- a_auth0_ids_user
, '' -- a_names_user
, '' -- a_emails_user
, 1 -- a_require_all_id_search_filters_met
, 1 -- a_require_any_id_search_filters_met
, 0 -- a_require_all_non_id_search_filters_met
, 0 -- a_require_any_non_id_search_filters_met
, v_id_permission_dog_new -- ids_permission
, v_id_access_level_edit -- ids_access_level
, 0 -- a_show_errors
, 0 -- a_debug
);
SELECT
IFNULL(CU_T.has_access, 0)
INTO
v_can_create
FROM parts.DOG_Calc_User_Temp CU_T
WHERE CU_T.GUID = a_guid
LIMIT 1
;
CALL parts.p_dog_clear_calc_user(
a_guid
, 0 -- a_debug
);
IF v_can_create = 0 THEN
DELETE t_ME
FROM tmp_Msg_Error t_ME
WHERE t_ME.id_type <> v_id_type_error_no_permission
;
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
VALUES (
v_id_type_error_no_permission
, v_code_type_error_no_permission
, 'You do not have permission to edit Assessment_Command_Modality_Links.'
)
;
END IF;
IF EXISTS (SELECT * FROM tmp_Msg_Error t_ERROR INNER JOIN parts.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type WHERE ERROR_TYPE.is_breaking_error = 1 LIMIT 1) THEN
IF a_debug = 1 THEN
SELECT * from tmp_Assessment_Command_Modality_Link;
END IF;
DELETE FROM tmp_Assessment_Command_Modality_Link;
END IF;
IF NOT EXISTS (SELECT * FROM tmp_Msg_Error t_ERROR INNER JOIN parts.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type WHERE ERROR_TYPE.is_breaking_error = 1 LIMIT 1) THEN
START TRANSACTION;
INSERT INTO parts.DOG_Dog_Change_Set (
comment
, id_user_updated_last_by
, updated_last_on
)
VALUES (
a_comment
, a_id_user
, v_time_start
)
;
SET v_id_change_set := LAST_INSERT_ID();
UPDATE parts.DOG_Assessment_Command_Modality_Link ASSESSMENT_COMMAND_MODALITY_LINK
INNER JOIN tmp_Assessment_Command_Modality_Link t_ASSESSMENT_COMMAND_MODALITY_LINK
ON ASSESSMENT_COMMAND_MODALITY_LINK.id_link = t_ASSESSMENT_COMMAND_MODALITY_LINK.id_link
AND t_ASSESSMENT_COMMAND_MODALITY_LINK.is_new = 0
SET
ASSESSMENT_COMMAND_MODALITY_LINK.id_assessment = t_ASSESSMENT_COMMAND_MODALITY_LINK.id_assessment
, ASSESSMENT_COMMAND_MODALITY_LINK.id_command = t_ASSESSMENT_COMMAND_MODALITY_LINK.id_command
, ASSESSMENT_COMMAND_MODALITY_LINK.id_command_modality = t_ASSESSMENT_COMMAND_MODALITY_LINK.id_command_modality
, ASSESSMENT_COMMAND_MODALITY_LINK.id_bribe = t_ASSESSMENT_COMMAND_MODALITY_LINK.id_bribe
, ASSESSMENT_COMMAND_MODALITY_LINK.id_distance_from_handler = t_ASSESSMENT_COMMAND_MODALITY_LINK.id_distance_from_handler
, ASSESSMENT_COMMAND_MODALITY_LINK.id_is_in_sight_of_handler = t_ASSESSMENT_COMMAND_MODALITY_LINK.id_is_in_sight_of_handler
, ASSESSMENT_COMMAND_MODALITY_LINK.id_is_in_scent_range_of_handler = t_ASSESSMENT_COMMAND_MODALITY_LINK.id_is_in_scent_range_of_handler
, ASSESSMENT_COMMAND_MODALITY_LINK.is_in_hearing_range_of_handler = t_ASSESSMENT_COMMAND_MODALITY_LINK.is_in_hearing_range_of_handler
, ASSESSMENT_COMMAND_MODALITY_LINK.is_on_lead = t_ASSESSMENT_COMMAND_MODALITY_LINK.is_on_lead
, ASSESSMENT_COMMAND_MODALITY_LINK.trial_count = t_ASSESSMENT_COMMAND_MODALITY_LINK.trial_count
, ASSESSMENT_COMMAND_MODALITY_LINK.active = t_ASSESSMENT_COMMAND_MODALITY_LINK.active
, ASSESSMENT_COMMAND_MODALITY_LINK.id_change_set = v_id_change_set
;
INSERT INTO parts.DOG_Assessment_Command_Modality_Link (
id_assessment
, id_command
, id_command_modality
, id_bribe
, id_distance_from_handler
, id_is_in_sight_of_handler
, id_is_in_scent_range_of_handler
, is_in_hearing_range_of_handler
, is_on_lead
, trial_count
, active
, id_user_created_by
, created_on
)
SELECT
t_ASSESSMENT_COMMAND_MODALITY_LINK.id_assessment AS id_assessment
, t_ASSESSMENT_COMMAND_MODALITY_LINK.id_command AS id_command
, t_ASSESSMENT_COMMAND_MODALITY_LINK.id_command_modality AS id_command_modality
, t_ASSESSMENT_COMMAND_MODALITY_LINK.id_bribe AS id_bribe
, t_ASSESSMENT_COMMAND_MODALITY_LINK.id_distance_from_handler AS id_distance_from_handler
, t_ASSESSMENT_COMMAND_MODALITY_LINK.id_is_in_sight_of_handler AS id_is_in_sight_of_handler
, t_ASSESSMENT_COMMAND_MODALITY_LINK.id_is_in_scent_range_of_handler AS id_is_in_scent_range_of_handler
, t_ASSESSMENT_COMMAND_MODALITY_LINK.is_in_hearing_range_of_handler AS is_in_hearing_range_of_handler
, t_ASSESSMENT_COMMAND_MODALITY_LINK.is_on_lead AS is_on_lead
, t_ASSESSMENT_COMMAND_MODALITY_LINK.trial_count AS trial_count
, t_ASSESSMENT_COMMAND_MODALITY_LINK.active AS active
, a_id_user AS created_by
, v_time_start AS created_on
FROM tmp_Assessment_Command_Modality_Link t_ASSESSMENT_COMMAND_MODALITY_LINK
WHERE
t_ASSESSMENT_COMMAND_MODALITY_LINK.is_new = 1
AND t_ASSESSMENT_COMMAND_MODALITY_LINK.active = 1
;
COMMIT;
END IF;
START TRANSACTION;
DELETE FROM parts.DOG_Assessment_Command_Modality_Link_Temp
WHERE GUID = a_guid
;
COMMIT;
-- Errors
SELECT
t_ERROR.id_error
, t_ERROR.id_type
, t_ERROR.code
, ERROR_TYPE.name
, ERROR_TYPE.description
, ERROR_TYPE.is_breaking_error
, ERROR_TYPE.background_colour
, ERROR_TYPE.text_colour
, t_ERROR.msg
FROM tmp_Msg_Error t_ERROR
INNER JOIN parts.CORE_Msg_Error_Type ERROR_TYPE ON t_ERROR.id_type = ERROR_TYPE.id_type
;
IF a_debug = 1 THEN
SELECT * FROM tmp_Assessment_Command_Modality_Link;
END IF;
DROP TEMPORARY TABLE tmp_Assessment_Command_Modality_Link;
DROP TEMPORARY TABLE tmp_Msg_Error;
IF a_debug = 1 THEN
CALL parts.p_core_debug_timing_reporting ( v_time_start );
END IF;
END //
DELIMITER ;
/*
'ripplesipplenippletippledipplekipple'
DELETE FROM parts.DOG_Assessment_Command_Modality_Link WHERE id_link > 740;
* /
delete
from parts.DOG_Assessment_Command_Modality_Link_Audit
where id_link > 768
;
delete
from parts.DOG_Assessment_Command_Modality_Link
where id_link > 768
;
delete
from parts.DOG_Assessment_Command_Modality_Link_Temp
;
select
*
-- COUNT(*)
-- delete
from parts.DOG_Assessment_Command_Modality_Link_Temp
;
select COUNT(*)
from parts.DOG_Assessment_Command_Modality_Link_Temp
;
select
*
-- COUNT(*)
-- delete
from parts.DOG_Assessment_Command_Modality_Link
;
select COUNT(*)
from parts.DOG_Assessment_Command_Modality_Link
;
INSERT INTO parts.DOG_Assessment_Command_Modality_Link_Temp (
id_link
, id_dog
, id_command
, hand_signal_description
, trial_count
, active
, guid
)
VALUES (
-1 -- id_link
, 1 -- id_dog
, 1 -- id_command
, 'Test deez noots' -- hand_signal_description
, NULL -- trial_count
, 1 -- active
, 'ripplesipplenippletippledipplekipple'
);
CALL parts.p_dog_save_assessment_command_modality_link (
'nipples'
, 'ripplesipplenippletippledipplekipple'
, 1
, 1
);
select
*
-- COUNT(*)
-- delete
from parts.DOG_Assessment_Command_Modality_Link_Temp
;
select COUNT(*)
from parts.DOG_Assessment_Command_Modality_Link_Temp
;
select
*
-- COUNT(*)
-- delete
from parts.DOG_Assessment_Command_Modality_Link
;
select COUNT(*)
from parts.DOG_Assessment_Command_Modality_Link
;
*/

View File

@@ -0,0 +1,436 @@
USE parts;
DROP PROCEDURE IF EXISTS parts.p_ph_save_contact_form;
DELIMITER //
CREATE PROCEDURE parts.p_ph_save_contact_form (
IN a_comment VARCHAR(500),
IN a_guid BINARY(36),
IN a_id_user INT,
IN a_debug BIT
)
BEGIN
DECLARE v_code_type_error_bad_data VARCHAR(100);
DECLARE v_id_access_level_view INT;
DECLARE v_id_access_level_edit INT;
DECLARE v_id_change_set INT;
DECLARE v_id_permission_contact_form_admin INT;
DECLARE v_id_permission_contact_form_new INT;
DECLARE v_id_type_error_bad_data INT;
DECLARE v_time_start TIMESTAMP(6);
DECLARE v_can_admin BIT;
DECLARE v_can_create BIT;
DECLARE exit handler for SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
@sqlstate = RETURNED_SQLSTATE
, @errno = MYSQL_ERRNO
, @text = MESSAGE_TEXT
;
ROLLBACK;
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_Msg_Error (
display_order INT NOT NULL PRIMARY KEY AUTO_INCREMENT
, id_type INT NULL
, code VARCHAR(50) NOT NULL
, msg VARCHAR(4000) NOT NULL
);
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
MET.id_type
, @errno
, @text
FROM parts.CORE_Msg_Error_Type MET
WHERE MET.code = 'MYSQL_ERROR'
;
SELECT *
FROM tmp_Msg_Error;
DROP TABLE IF EXISTS tmp_Msg_Error
;
END;
SET v_time_start := CURRENT_TIMESTAMP(6);
SET v_code_type_error_bad_data := 'BAD_DATA';
SET v_id_type_error_bad_data := (SELECT id_type FROM parts.CORE_Msg_Error_Type WHERE code = v_code_type_error_bad_data LIMIT 1);
SET v_id_permission_contact_form_admin := (SELECT id_permission FROM parts.DOG_Permission P WHERE P.code = 'CONTACT_FORM_ADMIN' LIMIT 1);
SET v_id_permission_contact_form_new := (SELECT id_permission FROM parts.DOG_Permission P WHERE P.code = 'CONTACT_FORM_CREATE' LIMIT 1);
CALL parts.p_core_validate_guid ( a_guid );
DROP TABLE IF EXISTS tmp_Contact_Form;
CREATE TEMPORARY TABLE tmp_Contact_Form (
id_contact_form INT NOT NULL
, email VARCHAR(255) NOT NULL
, name_contact VARCHAR(255) NOT NULL
, name_company VARCHAR(255) NOT NULL
, message TEXT NOT NULL
, receive_marketing_communications BIT NOT NULL
, active BIT NOT NULL
, name_error VARCHAR(255)
, is_new BIT NOT NULL
);
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_Msg_Error (
display_order INT NOT NULL PRIMARY KEY AUTO_INCREMENT
, id_type INT NULL
, code VARCHAR(50) NOT NULL
, msg VARCHAR(4000) NOT NULL
);
-- Get data from Temp table
INSERT INTO tmp_Contact_Form (
id_contact_form
, email
, name_contact
, name_company
, message
, receive_marketing_communications
, active
, is_new
)
SELECT
CF_T.id_contact_form AS id_contact_form
, IFNULL(CF_T.email, CF.email) AS code
, IFNULL(CF_T.name_contact, CF.name_contact) AS name_contact
, IFNULL(CF_T.name_company, CF.name_company) AS name_company
, IFNULL(CF_T.message, CF.message) AS message
, COALESCE(CF_T.receive_marketing_communications, CF.receive_marketing_communications, 0) AS receive_marketing_communications
, COALESCE(CF_T.active, CF.active, 1) AS active
, CASE WHEN IFNULL(CF_T.id_contact_form, 0) < 1 THEN 1 ELSE 0 END AS is_new
FROM parts.PH_Contact_Form_Temp CF_T
LEFT JOIN parts.PH_Contact_Form CF ON CF_T.id_contact_form = CF.id_contact_form
WHERE CF_T.guid = a_guid
;
UPDATE tmp_Contact_Form t_CF
SET name_error = COALESCE(t_CF.email, t_CF.name_company, t_CF.name_contact, t_CF.message, '(No Contact Form)')
;
-- Validation
-- Missing mandatory fields
-- email
IF EXISTS (SELECT * FROM tmp_Contact_Form t_CF WHERE ISNULL(t_CF.email) LIMIT 1) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Contact Form(s) do not have an Email: ', GROUP_CONCAT(t_CF.name_error SEPARATOR ', ')) AS msg
FROM tmp_Contact_Form t_CF
WHERE ISNULL(t_CF.email)
;
END IF;
-- name_contact
IF EXISTS (SELECT * FROM tmp_Contact_Form t_CF WHERE ISNULL(t_CF.name_contact) LIMIT 1) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Contact Form(s) do not have a Contact Name: ', GROUP_CONCAT(t_CF.name_error SEPARATOR ', ')) AS msg
FROM tmp_Contact_Form t_CF
WHERE ISNULL(t_CF.name_contact)
;
END IF;
-- name_company
IF EXISTS (SELECT * FROM tmp_Contact_Form t_CF WHERE ISNULL(t_CF.name_company) LIMIT 1) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Contact Form(s) do not have a Company Name: ', GROUP_CONCAT(t_CF.name_error SEPARATOR ', ')) AS msg
FROM tmp_Contact_Form t_CF
WHERE ISNULL(t_CF.name)
;
END IF;
-- message
IF EXISTS (SELECT * FROM tmp_Contact_Form t_CF WHERE ISNULL(t_CF.message) LIMIT 1) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('The following Contact Form(s) do not have a Message: ', GROUP_CONCAT(t_CF.name_error SEPARATOR ', ')) AS msg
FROM tmp_Contact_Form t_CF
WHERE ISNULL(t_CF.message)
;
END IF;
-- Permissions
IF a_debug = 1 THEN
SELECT
a_guid
, 0 -- get_all_user
, 0 -- get_inactive_user
, a_id_user -- ids_user
, '' -- a_auth0_ids_user
, '' -- a_names_user
, '' -- a_emails_user
, 1 -- a_require_all_id_search_filters_met
, 1 -- a_require_any_id_search_filters_met
, 0 -- a_require_all_non_id_search_filters_met
, 0 -- a_require_any_non_id_search_filters_met
, v_id_permission_contact_form_admin -- ids_permission
, v_id_access_level_view -- ids_access_level
, 0 -- a_show_errors
, 0 -- a_debug
;
END IF;
CALL parts.p_dog_calc_user(
a_guid
, 0 -- get_all_user
, 0 -- get_inactive_user
, a_id_user -- ids_user
, '' -- a_auth0_ids_user
, '' -- a_names_user
, '' -- a_emails_user
, 1 -- a_require_all_id_search_filters_met
, 1 -- a_require_any_id_search_filters_met
, 0 -- a_require_all_non_id_search_filters_met
, 0 -- a_require_any_non_id_search_filters_met
, v_id_permission_contact_form_admin -- ids_permission
, v_id_access_level_view -- ids_access_level
, 0 -- a_show_errors
, 0 -- a_debug
);
SELECT
IFNULL(CALC_USER_T.has_access, 0)
INTO
v_can_admin
FROM parts.DOG_Calc_User_Temp CALC_USER_T
WHERE CALC_USER_T.GUID = a_guid
LIMIT 1
;
IF a_debug = 1 THEN
SELECT v_can_admin;
SELECT COUNT(*) AS Count_Errors FROM tmp_Msg_Error t_ERROR;
SELECT * FROM tmp_Msg_Error t_ERROR;
END IF;
CALL parts.p_dog_clear_calc_user(
a_guid
, 0 -- a_debug
);
IF a_debug = 1 THEN
SELECT
a_guid
, 0 -- get_all_user
, 0 -- get_inactive_user
, a_id_user -- ids_user
, '' -- a_auth0_ids_user
, '' -- a_names_user
, '' -- a_emails_user
, 1 -- a_require_all_id_search_filters_met
, 1 -- a_require_any_id_search_filters_met
, 0 -- a_require_all_non_id_search_filters_met
, 0 -- a_require_any_non_id_search_filters_met
, v_id_permission_contact_form_new -- ids_permission
, v_id_access_level_view -- ids_access_level
, 0 -- a_show_errors
, 0 -- a_debug
;
END IF;
CALL parts.p_dog_calc_user(
a_guid
, 0 -- get_all_user
, 0 -- get_inactive_user
, a_id_user -- ids_user
, '' -- a_auth0_ids_user
, '' -- a_names_user
, '' -- a_emails_user
, 1 -- a_require_all_id_search_filters_met
, 1 -- a_require_any_id_search_filters_met
, 0 -- a_require_all_non_id_search_filters_met
, 0 -- a_require_any_non_id_search_filters_met
, v_id_permission_contact_form_new -- ids_permission
, v_id_access_level_view -- ids_access_level
, 0 -- a_show_errors
, 0 -- a_debug
);
SELECT
IFNULL(CALC_USER_T.has_access, 0)
INTO
v_can_create
FROM parts.DOG_Calc_User_Temp CALC_USER_T
WHERE CALC_USER_T.GUID = a_guid
LIMIT 1
;
IF a_debug = 1 THEN
SELECT v_can_create;
SELECT COUNT(*) AS Count_Errors FROM tmp_Msg_Error t_ERROR;
SELECT * FROM tmp_Msg_Error t_ERROR;
END IF;
CALL parts.p_dog_clear_calc_user(
a_guid
, 0 -- a_debug
);
IF (v_can_admin = 0 AND EXISTS(SELECT * FROM tmp_Contact_Form WHERE is_new = 0)) THEN
DELETE t_ME
FROM tmp_Msg_Error t_ME
WHERE t_ME.id_type <> v_id_type_error_no_permission
;
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
VALUES (
v_id_type_error_no_permission
, v_code_type_error_no_permission
, 'You do not have permission to admin Contact Forms.'
)
;
END IF;
IF EXISTS (SELECT * FROM tmp_Msg_Error LIMIT 1) THEN
IF a_debug = 1 THEN
SELECT * from tmp_Contact_Form;
END IF;
DELETE FROM tmp_Contact_Form;
END IF;
IF NOT EXISTS (SELECT * FROM tmp_Msg_Error LIMIT 1) THEN
START TRANSACTION;
INSERT INTO parts.PH_Contact_Form_Change_Set (
comment
, id_user_updated_last_by
, updated_last_on
)
VALUES (
a_comment
, a_id_user
, v_time_start
)
;
SET v_id_change_set := LAST_INSERT_ID();
UPDATE parts.PH_Contact_Form CF
INNER JOIN tmp_Contact_Form t_CF
ON CF.id_contact_form = t_CF.id_contact_form
AND t_CF.is_new = 0
SET
CF.email = t_CF.email
, CF.name_contact = t_CF.name_contact
, CF.name_company = t_CF.name_company
, CF.message = t_CF.message
, CF.receive_marketing_communications = t_CF.receive_marketing_communications
, CF.active = t_CF.active
, CF.id_change_set = v_id_change_set
;
INSERT INTO parts.PH_Contact_Form (
email
, name_contact
, name_company
, message
, receive_marketing_communications
, active
, id_user_created_by
, created_on
)
SELECT
t_CF.email AS email
, t_CF.name_contact AS name_contact
, t_CF.name_company AS name_company
, t_CF.message AS message
, t_CF.receive_marketing_communications AS receive_marketing_communications
, t_CF.active AS active
, a_id_user AS created_by
, v_time_start AS created_on
FROM tmp_Contact_Form t_CF
WHERE
t_CF.is_new = 1
AND t_CF.active = 1
;
COMMIT;
END IF;
START TRANSACTION;
DELETE FROM parts.PH_Contact_Form_Temp
WHERE GUID = a_guid
;
COMMIT;
-- Errors
SELECT *
FROM tmp_Msg_Error t_ME
INNER JOIN parts.CORE_Msg_Error_Type MET ON t_ME.id_type = MET.id_type
;
IF a_debug = 1 THEN
SELECT * from tmp_Contact_Form;
END IF;
DROP TEMPORARY TABLE tmp_Contact_Form;
DROP TEMPORARY TABLE tmp_Msg_Error;
IF a_debug = 1 THEN
CALL parts.p_core_debug_timing_reporting ( v_time_start );
END IF;
END //
DELIMITER ;
/*
select
*
-- COUNT(*)
-- delete
from parts.PH_Contact_Form_Temp
;
CALL parts.p_ph_save_contact_form (
'nipples'
, (SELECT GUID FROM parts.PH_Contact_Form_Temp ORDER BY id_temp DESC LIMIT 1)
, 1
, 1
);
select
*
-- COUNT(*)
-- delete
from parts.PH_Contact_Form_Temp
;
*/

View File

@@ -0,0 +1,277 @@
USE parts;
DROP PROCEDURE IF EXISTS parts.p_ph_get_many_contact_form;
DELIMITER //
CREATE PROCEDURE parts.p_ph_get_many_contact_form (
IN a_id_user INT
, IN a_get_all_contact_form BIT
, IN a_get_inactive_contact_form BIT
, IN a_ids_contact_form VARCHAR(500)
, IN a_debug BIT
)
BEGIN
DECLARE v_has_filter_contact_form BIT;
DECLARE v_guid BINARY(36);
DECLARE v_id_access_level_admin INT;
DECLARE v_id_permission_contact_form_admin INT;
DECLARE v_id_minimum INT;
DECLARE v_time_start TIMESTAMP(6);
DECLARE v_can_view BIT;
SET v_time_start := CURRENT_TIMESTAMP(6);
SET v_guid := UUID();
SET v_id_access_level_admin := (SELECT ACCESS_LEVEL.id_access_level FROM parts.DOG_Access_Level ACCESS_LEVEL WHERE ACCESS_LEVEL.code = 'ADMIN' LIMIT 1);
SET v_id_permission_contact_form_admin := (SELECT PERMISSION.id_permission FROM parts.DOG_Permission PERMISSION WHERE PERMISSION.code = 'CONTACT_FORM_ADMIN' LIMIT 1);
SET a_id_user := IFNULL(a_id_user, 0);
SET a_get_all_contact_form := IFNULL(a_get_all_contact_form, 0);
SET a_get_inactive_contact_form := IFNULL(a_get_inactive_contact_form, 0);
SET a_ids_contact_form := TRIM(IFNULL(a_ids_contact_form, ''));
SET a_debug := IFNULL(a_debug, 0);
IF a_debug = 1 THEN
SELECT
a_id_user
, a_get_all_contact_form
, a_get_inactive_contact_form
, a_ids_contact_form
, a_debug
;
END IF;
DROP TEMPORARY TABLE IF EXISTS tmp_Split;
DROP TEMPORARY TABLE IF EXISTS tmp_Contact_Form;
CREATE TEMPORARY TABLE tmp_Contact_Form (
id_contact_form INT NOT NULL
);
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_Msg_Error (
display_order INT NOT NULL PRIMARY KEY AUTO_INCREMENT
, id_type INT NULL
, code VARCHAR(50) NOT NULL
, msg VARCHAR(4000) NOT NULL
);
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_Split (
substring VARCHAR(4000) NOT NULL
, as_int INT NULL
);
DELETE FROM tmp_Split;
CALL parts.p_core_validate_guid ( v_guid );
SET v_has_filter_contact_form = CASE WHEN a_ids_contact_form = '' THEN 0 ELSE 1 END;
-- Contact Forms
IF v_has_filter_contact_form = 1 THEN
CALL parts.p_split(v_guid, a_ids_contact_form, ',', a_debug);
INSERT INTO tmp_Split (
substring
, as_int
)
SELECT
substring
, CONVERT(substring, DECIMAL(10,0)) AS as_int
FROM parts.CORE_Split_Temp
WHERE
GUID = v_guid
AND NOT ISNULL(substring)
AND substring != ''
;
CALL parts.p_clear_split_temp( v_guid );
END IF;
IF NOT EXISTS (SELECT * FROM tmp_Msg_Error LIMIT 1) THEN
IF EXISTS (
SELECT *
FROM tmp_Split t_S
LEFT JOIN parts.PH_Contact_Form CF ON t_S.as_int = CF.id_contact_form
WHERE
ISNULL(t_S.as_int)
OR ISNULL(CF.id_contact_form)
OR (
CF.active = 0
AND a_get_inactive_contact_form = 0
)
) THEN
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
SELECT
v_id_type_error_bad_data
, v_code_type_error_bad_data
, CONCAT('Invalid or inactive Contact Form IDs: ', IFNULL(GROUP_CONCAT(t_S.substring SEPARATOR ', '), 'NULL'))
FROM tmp_Split t_S
LEFT JOIN parts.PH_Contact_Form CF ON t_S.as_int = CF.id_contact_form
WHERE
ISNULL(t_S.as_int)
OR ISNULL(CF.id_contact_form)
OR (
CF.active = 0
AND a_get_inactive_contact_form = 0
)
;
ELSE
INSERT INTO tmp_Contact_Form (
id_contact_form
)
SELECT
CF.id_contact_form
FROM tmp_Split t_S
RIGHT JOIN parts.PH_Contact_Form CF ON t_S.as_int = CF.id_contact_form
WHERE
(
a_get_all_contact_form = 1
OR (
v_has_filter_contact_form = 1
AND NOT ISNULL(t_S.as_int)
)
)
AND (
a_get_inactive_contact_form = 1
OR CF.active = 1
)
;
END IF;
END IF;
DELETE FROM tmp_Split;
-- Permissions
IF a_debug = 1 THEN
SELECT
v_guid
, 0 -- get_all_user
, 0 -- get_inactive_user
, a_id_user -- ids_user
, '' -- a_auth0_ids_user
, '' -- a_names_user
, '' -- a_emails_user
, 1 -- a_require_all_id_search_filters_met
, 1 -- a_require_any_id_search_filters_met
, 0 -- a_require_all_non_id_search_filters_met
, 0 -- a_require_any_non_id_search_filters_met
, v_id_permission_contact_form_admin -- ids_permission
, v_id_access_level_admin -- ids_access_level
, 0 -- a_show_errors
, 0 -- a_debug
;
END IF;
CALL parts.p_dog_calc_user(
v_guid
, 0 -- get_all_user
, 0 -- get_inactive_user
, a_id_user -- ids_user
, '' -- a_auth0_ids_user
, '' -- a_names_user
, '' -- a_emails_user
, 1 -- a_require_all_id_search_filters_met
, 1 -- a_require_any_id_search_filters_met
, 0 -- a_require_all_non_id_search_filters_met
, 0 -- a_require_any_non_id_search_filters_met
, v_id_permission_contact_form_admin -- ids_permission
, v_id_access_level_admin -- ids_access_level
, 0 -- a_show_errors
, 0 -- a_debug
);
SELECT
IFNULL(CALC_USER_T.has_access, 0)
INTO
v_can_view
FROM parts.DOG_Calc_User_Temp CALC_USER_T
WHERE CALC_USER_T.GUID = v_guid
LIMIT 1
;
IF a_debug = 1 THEN
SELECT v_can_view;
SELECT COUNT(*) AS Count_Errors FROM tmp_Msg_Error t_ERROR;
SELECT * FROM tmp_Msg_Error t_ERROR;
END IF;
IF (v_can_view = 0) THEN
DELETE t_ME
FROM tmp_Msg_Error t_ME
WHERE t_ME.id_type <> v_id_type_error_no_permission
;
INSERT INTO tmp_Msg_Error (
id_type
, code
, msg
)
VALUES (
v_id_type_error_no_permission
, v_code_type_error_no_permission
, 'You do not have permission to view Contact Forms.'
)
;
IF a_debug = 1 THEN
SELECT * FROM tmp_Contact_Form;
END IF;
DELETE FROM tmp_Contact_Form;
END IF;
CALL parts.p_dog_clear_calc_user(
v_guid
, 0 -- a_debug
);
-- Outputs
-- Contact Forms
SELECT
t_CF.id_contact_form
, CF.email
, CF.name_contact
, CF.name_company
, CF.message
, CF.active
, v_can_view
FROM tmp_Contact_Form t_CF
INNER JOIN parts.PH_Contact_Form CF ON t_CF.id_contact_form = CF.id_contact_form
GROUP BY t_CF.id_contact_form
ORDER BY CF.created_on DESC
;
-- Errors
SELECT *
FROM tmp_Msg_Error t_ME
INNER JOIN parts.CORE_Msg_Error_Type MET ON t_ME.id_type = MET.id_type
;
IF a_debug = 1 AND v_can_view = 1 THEN
SELECT * FROM tmp_Contact_Form;
END IF;
DROP TEMPORARY TABLE IF EXISTS tmp_Split;
DROP TEMPORARY TABLE IF EXISTS tmp_Contact_Form;
IF a_debug = 1 THEN
CALL parts.p_core_debug_timing_reporting ( v_time_start );
END IF;
END //
DELIMITER ;
/*
CALL parts.p_ph_get_many_contact_form (
1 -- 'auth0|6582b95c895d09a70ba10fef', -- a_id_user
, 1 -- a_get_all_contact_form
, 0 -- a_get_inactive_contact_form
, '' -- a_ids_contact_form
, 0 -- a_debug
);
*/

View File

@@ -99,7 +99,12 @@ VALUES
, ( , (
1 1
, 'USER' , 'USER'
, 'Admin User' , 'User'
)
, (
2
, 'PROJECT_HUB'
, 'Project Hub'
) )
; ;
@@ -154,6 +159,20 @@ VALUES
, 2 , 2
, 2 , 2
) )
, (
1
, 'CONTACT_FORM_ADMIN'
, 'Admin Contact Form'
, 3
, 3
)
, (
1
, 'CONTACT_FORM_CREATE'
, 'Create Contact Form'
, 3
, 4
)
; ;
-- Users -- Users
@@ -265,6 +284,18 @@ VALUES
, 6 , 6
, 3 , 3
, 1 , 1
)
, (
1
, 7
, 3
, 1
)
, (
1
, 8
, 3
, 1
) )
, ( , (
2 2
@@ -302,6 +333,18 @@ VALUES
, 1 , 1
, 1 , 1
) )
, (
2
, 7
, 4
, 1
)
, (
2
, 8
, 1
, 1
)
; ;
-- User Role link -- User Role link

View File

@@ -0,0 +1,108 @@
USE parts;
DROP PROCEDURE IF EXISTS parts.p_ph_test_save_contact_form;
DELIMITER //
CREATE PROCEDURE parts.p_ph_test_save_contact_form ()
BEGIN
DECLARE v_guid BINARY(36);
DECLARE v_time_start TIMESTAMP(6);
SET v_time_start := CURRENT_TIMESTAMP(6);
SET v_guid := 'nipple_ripple_chipple_spittle_pickle'; -- 123456789012345678901234567890123456
SELECT 'Start of Test';
SELECT *
FROM parts.PH_Contact_Form
;
SELECT *
FROM parts.PH_Contact_Form_Temp
;
START TRANSACTION;
INSERT INTO parts.PH_Contact_Form_Temp (
id_contact_form
, email
, name_contact
, name_company
, message
, guid
, active
)
/*
VALUES (
-1 -- id_contact_form
, 'edward.middletonsmith@gmail.com' -- email
, 'Teddy' -- name_contact
, 'PARTS Ltd' -- name_company
, 'Sa dude' -- message
, v_guid
)
*/
VALUES (
-1 -- id_contact_form
, 'edward.middletonsmith@gmail.com' -- email
, 'Teddy' -- name_contact
, 'PARTS Ltd' -- name_company
, 'hegrodorf is good' -- message
, v_guid
, 1 -- active
)
;
COMMIT;
SELECT *
FROM parts.PH_Contact_Form_Temp
-- WHERE GUID = v_guid
;
CALL parts.p_ph_save_contact_form (
'Test save Contact Form' -- comment
, v_guid -- guid
, 3 -- 1 -- id_user
, 1 -- debug
);
SELECT *
FROM parts.PH_Contact_Form
;
SELECT *
FROM parts.PH_Contact_Form_Temp
;
CALL parts.p_debug_timing_reporting ( v_time_start );
END //
DELIMITER ;
/*
SELECT 'Before Test';
SELECT *
FROM parts.PH_Contact_Form
;
SELECT *
FROM parts.PH_Contact_Form_Temp
;
CALL parts.p_ph_test_save_contact_form ();
SELECT 'After Test';
SELECT *
FROM parts.PH_Contact_Form
;
SELECT *
FROM parts.PH_Contact_Form_Temp
;
DELETE FROM parts.PH_Contact_Form_Temp;
DROP TABLE IF EXISTS tmp_Msg_Error;
*/

View File

@@ -1,34 +1 @@
/* In sections */
/* Footer */
.footer {
padding: 1vh 1vw;
text-align: center;
margin: 0;
max-height: 5vh;
overflow-y: auto;
background-color: var(--colour-accent);
position: absolute;
bottom: 0;
width: 98vw;
}
@media screen and (max-width: 400px) {
.footer {
max-height: 8vh;
padding: 0 2vw;
font-size: 10px;
width: 96vw;
max-width: 96vw;
}
.footer > h4 {
font-size: 10px;
}
.footer > h5 {
font-size: 9px;
}
}
.footer > h4, h5 {
padding: 0;
margin: 0;
}

View File

@@ -1,43 +1,4 @@
/*
header {
background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
/ * position: fixed;
top: 0; * /
width: 100%;
z-index: 1000;
}
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 0;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
color: var(--primary);
}
.nav-links {
display: flex;
gap: 2rem;
}
.nav-links a {
text-decoration: none;
color: var(--text);
font-weight: 500;
align-content: center;
}
.nav-links a.button {
color: white;
}
*/
/* Navigation */ /* Navigation */
.topnav { .topnav {

View File

@@ -59,8 +59,9 @@ script, link {
display: none !important; display: none !important;
} }
/*
#pageBody { #pageBody {
/* height: 69vh !important; */ / * height: 69vh !important; * /
max-height: 79vh; max-height: 79vh;
padding: 0 5vw; padding: 0 5vw;
margin: 0; margin: 0;
@@ -76,6 +77,7 @@ script, link {
width: 90vw; width: 90vw;
color: var(--colour-text); color: var(--colour-text);
} }
*/
.page-body > * { .page-body > * {
display: flex; display: flex;
@@ -117,7 +119,7 @@ img.header-logo {
background-color: var(--colour-text-background); background-color: var(--colour-text-background);
padding: 1vh 2.5vw; padding: 1vh 2.5vw;
margin: 1vh; margin: 1vh;
display: flex !important; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -210,6 +212,8 @@ img.header-logo {
ul { ul {
max-width: 90%; max-width: 90%;
padding: 5px 0 10px 0; padding: 5px 0 10px 0;
width: fit-content;
margin: auto;
} }
li { li {
text-align: left; text-align: left;

View File

@@ -0,0 +1,135 @@
.contact-section {
padding: 2rem 2rem 4rem;
}
.contact-section h1 {
margin: 1rem auto;
}
.contact-section p {
margin: 0.5rem auto;
}
.contact-form {
max-width: 60vw;
width: fit-content;
margin: 0 auto;
background: #fff;
padding: 2rem;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.contact-form textarea {
max-width: 40vw;
}
.form-grid {
display: grid;
grid-template-columns: 200px 1fr;
gap: 1.5rem;
margin-bottom: 1rem;
}
.form-label {
padding-top: 0.5rem;
font-weight: 500;
}
.form-input {
width: 100%;
padding: 0.5rem;
border: 1px solid #d1d5db;
border-radius: 4px;
font-size: 1rem;
}
textarea.form-input {
min-height: 120px;
}
.marketing-consent input {
display: inline-block;
margin-left: 20%;
margin-bottom: 1.25rem;
}
.container.captcha > div:first-child > label:first-child {
display: flex;
justify-content: center;
width: fit-content;
text-align: center;
margin: 0 auto;
}
.container.captcha > p:last-child{
font-size: 0.9rem;
margin: 1vh 0;
}
.container.captcha .altcha-main {
padding-left: 1rem;
padding-top: 0.75rem;
padding-bottom: 0;
}
.container.captcha .altcha-main > :last-child {
display: none;
}
.container.captcha .altcha,
altcha-widget > div:first-child,
.container.captcha > div > .altcha-widget > div {
width: fit-content;
display: flex;
margin-left: auto;
margin-right: auto;
}
input[type="submit"] {
margin-left: 40%;
padding: 0.75rem 1.5rem;
background: #2563eb;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 1rem;
}
input[type="submit"]:hover {
background: #1d4ed8;
}
.data-notice {
margin-top: 3rem;
padding: 1.5rem;
background: #f3f4f6;
border-radius: 4px;
font-size: 0.95rem;
}
.data-notice h3 {
margin-bottom: 1rem;
font-size: 1.1rem;
}
.data-notice ul li {
list-style-position: inside;
}
@media (max-width: 768px) {
.contact-form {
max-width: 80vw;
}
.contact-form textarea {
max-width: 60vw;
}
.form-grid {
grid-template-columns: 1fr;
gap: 0.5rem;
}
.form-label {
padding-top: 0;
}
.submit-button {
margin-left: 0;
width: 100%;
}
}
@media (max-width: 400px) {
}

View File

@@ -1,66 +1,45 @@
/* Common */
/* Hero Section */ p {
.home-hero { width: 100%;
padding: 8rem 0 4rem; font-size: 16px;
align-self: center; }
margin-left: auto; p.section-title,
margin-right: auto; p.section-subtitle {
margin: 0 auto;
}
.section-subtitle {
font-size: 18px;
}
ul li {
font-size: 16px;
} }
.hero-content { section.problem,
max-width: 600px; section.benefits,
} section.features,
section.faq {
.home-hero h2 {
font-size: 24px;
line-height: 1.2;
margin-bottom: 1.5rem;
color: var(--colour-text);
margin-left: auto;
margin-right: auto;
}
.home-hero a {
font-size: 1.25rem;
margin-bottom: 2rem;
color: var(--colour-primary);
cursor: pointer;
margin-left: auto;
margin-right: auto;
}
/* Services Section */
.services {
padding: 6rem 0; padding: 6rem 0;
background: white; background: var(--colour-text-background);
} }
section.problem .card.problem,
.services-grid { section.benefits .card.benefits,
display: grid; section.features .card.features,
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); section.faq .card.faq {
gap: 2rem;
margin-top: 3rem;
}
.service-card {
padding: 2rem; padding: 2rem;
background: var(--light); background: var(--colour-page-background);
border-radius: 8px; border-radius: 8px;
transition: transform 0.3s ease; transition: transform 0.3s ease;
display: block;
} }
.service-card:hover { section.solution,
transform: translateY(-5px); section.social-proof {
}
/* Testimonial Section */
.testimonial {
padding: 6rem 0; padding: 6rem 0;
background: var(--light); background: var(--colour-page-background-1);
} }
section.solution .card.solution,
.testimonial-card { section.social-proof .card.social-proof {
background: white; background: var(--colour-text-background);
padding: 2rem; padding: 2rem;
border-radius: 8px; border-radius: 8px;
max-width: 800px; max-width: 800px;
@@ -68,14 +47,56 @@
box-shadow: 0 4px 6px rgba(0,0,0,0.1); box-shadow: 0 4px 6px rgba(0,0,0,0.1);
} }
/* Pricing Section */ /* Hero Section */
.pricing { .hero {
padding: 8rem 0 4rem;
background: linear-gradient(45deg, var(--colour-page-background-1), var(--colour-page-background-2)); /* linear-gradient(45deg, #f8fafc, #eff6ff); */
}
.hero-content {
max-width: 600px;
}
.hero h1 {
font-size: 3rem;
line-height: 1.2;
margin-bottom: 1.5rem;
color: var(--colour-text);
}
.hero p {
font-size: 1.25rem;
margin-bottom: 2rem;
color: var(--colour-secondary);
}
/* Problem Section */
/*
section.problem .problem.card:hover {
transform: translateY(-5px);
}
*/
/* Solution Section */
/* Benefits Section */
section.benefits .section-subtitle {
font-size: 18px;
font-weight: bold;
}
/* Social Proof Section * /
section.social-proof {
padding: 6rem 0; padding: 6rem 0;
background: white; background: white;
} }
.pricing-card { section.social-proof .card.social-proof {
background: var(--light); background: var(--colour-page-background);
padding: 2rem; padding: 2rem;
border-radius: 8px; border-radius: 8px;
text-align: center; text-align: center;
@@ -83,21 +104,63 @@
margin: 3rem auto 0; margin: 3rem auto 0;
} }
.price { section.social-proof ul {
font-size: 2.5rem; list-style: none;
color: var(--primary); margin: 0;
font-weight: bold; }
margin: 1rem 0; * /
section.social-proof .section-subtitle {
font-size: 16px;
}
*/
section.social-proof ul li {
font-size: 14px;
}
/* Early Access Section * /
section.early-access {
padding: 6rem 0;
background: white;
}
section.early-access .card.early-access {
background: var(--colour-page-background);
padding: 2rem;
border-radius: 8px;
text-align: center;
max-width: 400px;
margin: 3rem auto 0;
}
section.early-access ul {
list-style: none;
margin: 0;
}
section.early-access a.button {
margin: 0.25rem;
}
*/
/* Features section */
section.features .button {
margin-top: 0;
} }
/* CTA Section */ /* CTA Section */
.cta { .cta-1,
.cta-2 {
padding: 6rem 0; padding: 6rem 0;
background: var(--primary); background: var(--colour-primary);
color: white; color: white;
text-align: center; text-align: center;
} }
/* FAQs * /
section.faq .button {
margin-bottom: 0.25rem;
}
*/
/* Animations */ /* Animations */
/* Fallback styles to ensure content is visible without JS */ /* Fallback styles to ensure content is visible without JS */
@@ -130,4 +193,39 @@
.delay-1 { animation-delay: 0.1s; } .delay-1 { animation-delay: 0.1s; }
.delay-2 { animation-delay: 0.2s; } .delay-2 { animation-delay: 0.2s; }
.delay-3 { animation-delay: 0.3s; } .delay-3 { animation-delay: 0.3s; }
.delay-4 { animation-delay: 0.4s; } .delay-4 { animation-delay: 0.4s; }
/* Buttons */
.button {
display: inline-block;
padding: 0.75rem 1.5rem;
border-radius: 6px;
text-decoration: none;
font-weight: 500;
transition: all 0.3s ease;
width: fit-content;
margin: 0.75rem;
font-size: 18px;
}
.button-primary {
background: var(--colour-primary);
color: white;
}
.button-primary:hover {
background: var(--colour-secondary);
}
.button-light {
background: white;
color: var(--colour-primary);
}
.button-light:hover {
background: var(--colour-page-background);
}
.logo:hover{
cursor: pointer;
}

View File

@@ -0,0 +1,152 @@
/* Home page
*/
header {
background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
/* position: fixed;
top: 0; */
width: 100%;
z-index: 1000;
}
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 0;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
color: var(--primary);
}
.nav-links {
display: flex;
gap: 2rem;
display: flex;
flex-wrap: wrap;
max-width: 70vw;
}
.nav-links a {
text-decoration: none;
color: var(--text);
font-weight: 500;
align-content: center;
font-size: 1rem;
}
.nav-links a.button {
color: white;
margin: 0 auto;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 1.5rem;
}
/* Header */
header {
background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
/* position: fixed;
top: 0; */
width: 100%;
z-index: 1000;
}
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 0;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
color: var(--primary);
}
.nav-links {
display: flex;
gap: 2rem;
}
.nav-links a {
text-decoration: none;
color: var(--text);
font-weight: 500;
align-content: center;
}
.nav-links a.button {
color: white;
}
/* Footer */
.footer {
background: #1f2937;
color: #f3f4f6;
padding: 4rem 0 2rem;
}
.footer-content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 2rem;
margin-bottom: 2rem;
}
.footer-section h3 {
color: #fff;
margin-bottom: 1rem;
font-size: 1.2rem;
}
.footer-section ul {
list-style: none;
padding: 0;
}
.footer-section ul li {
margin-bottom: 0.5rem;
}
.footer-section a {
color: #f3f4f6;
text-decoration: none;
transition: color 0.3s ease;
}
.footer-section a:hover {
color: #fff;
text-decoration: underline;
}
.footer-bottom {
border-top: 1px solid #374151;
padding-top: 2rem;
text-align: center;
font-size: 0.9rem;
}
.footer-bottom a {
color: aquamarine;
}
@media (max-width: 768px) {
.footer-content {
grid-template-columns: 1fr;
text-align: center;
}
}
@media (max-width: 515px) {
.nav-links {
display: none;
}
}

View File

@@ -1,38 +1,4 @@
.img-product {
max-width: 20vh;
max-height: 20vh;
border-radius: 3vh;
justify-self: left;
}
.img-thumbnail {
max-width: 10vh;
max-height: 10vh;
border-radius: 3vh;
justify-self: left;
}
.buttonAddToBasket {
background-color: var(--colour-page-background);
border-color: var(--colour-primary);
}
#buttonCheckout, .buttonBuyNow {
background-color: var(--colour-page-background);
/* color: var(--c_purple_dark); */
border-color: var(--colour-primary);
}
.button-increment, .button-decrement {
border: 2px solid darkgrey;
background-color: lightgray;
margin: 1vh 1vh;
width: 2.5vh;
height: 2.5vh;
border-radius: 1.25vh;
font-size: 2vh;
}
.container-input > input { .container-input > input {
padding: 0vh 1vh; padding: 0vh 1vh;
@@ -53,3 +19,57 @@
/* Main Table */ /* Main Table */
#pageBody {
/* height: 69vh !important; */
max-height: 79vh;
padding: 0 5vw;
margin: 0;
border: 0;
align-content: center;
justify-content: flex-start;
display: flex;
flex-direction: column;
align-items: flex-start;
overflow-y: auto;
overflow-x: hidden;
position: absolute;
width: 90vw;
color: var(--colour-text);
}
/* Footer */
.footer {
padding: 1vh 1vw;
text-align: center;
margin: 0;
max-height: 5vh;
overflow-y: auto;
background-color: var(--colour-accent);
position: absolute;
bottom: 0;
width: 98vw;
}
@media screen and (max-width: 400px) {
.footer {
max-height: 8vh;
padding: 0 2vw;
font-size: 10px;
width: 96vw;
max-width: 96vw;
}
.footer > h4 {
font-size: 10px;
}
.footer > h5 {
font-size: 9px;
}
}
.footer > h4, h5 {
padding: 0;
margin: 0;
}

View File

@@ -1,3 +1,155 @@
/* Home page
*/
header {
background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
/* position: fixed;
top: 0; */
width: 100%;
z-index: 1000;
}
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 0;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
color: var(--primary);
}
.nav-links {
display: flex;
gap: 2rem;
display: flex;
flex-wrap: wrap;
max-width: 70vw;
}
.nav-links a {
text-decoration: none;
color: var(--text);
font-weight: 500;
align-content: center;
font-size: 1rem;
}
.nav-links a.button {
color: white;
margin: 0 auto;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 1.5rem;
}
/* Header */
header {
background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
/* position: fixed;
top: 0; */
width: 100%;
z-index: 1000;
}
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 0;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
color: var(--primary);
}
.nav-links {
display: flex;
gap: 2rem;
}
.nav-links a {
text-decoration: none;
color: var(--text);
font-weight: 500;
align-content: center;
}
.nav-links a.button {
color: white;
}
/* Footer */
.footer {
background: #1f2937;
color: #f3f4f6;
padding: 4rem 0 2rem;
}
.footer-content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 2rem;
margin-bottom: 2rem;
}
.footer-section h3 {
color: #fff;
margin-bottom: 1rem;
font-size: 1.2rem;
}
.footer-section ul {
list-style: none;
padding: 0;
}
.footer-section ul li {
margin-bottom: 0.5rem;
}
.footer-section a {
color: #f3f4f6;
text-decoration: none;
transition: color 0.3s ease;
}
.footer-section a:hover {
color: #fff;
text-decoration: underline;
}
.footer-bottom {
border-top: 1px solid #374151;
padding-top: 2rem;
text-align: center;
font-size: 0.9rem;
}
.footer-bottom a {
color: aquamarine;
}
@media (max-width: 768px) {
.footer-content {
grid-template-columns: 1fr;
text-align: center;
}
}
@media (max-width: 450px) {
.nav-links {
display: none;
}
}
#pageBody > .card:first-of-type { #pageBody > .card:first-of-type {
width: min(80vw, 500px); width: min(80vw, 500px);
} }

View File

@@ -1 +1 @@
{"version":3,"file":"css/core_admin_home.bundle.css","mappings":"AAAA;IACI,uBAAuB;AAC3B;;AAEA;IACI,WAAW;AACf,C","sources":["webpack://app/./static/css/pages/core/admin_home.css"],"sourcesContent":["#pageBody > .card:first-of-type {\n width: min(80vw, 500px);\n}\n\n.container.row {\n width: auto;\n}"],"names":[],"sourceRoot":""} {"version":3,"file":"css/core_admin_home.bundle.css","mappings":";AACA;CACC;AACD;IACI,iBAAiB;IACjB,qCAAqC;IACrC;aACS;IACT,WAAW;IACX,aAAa;AACjB;;AAEA;IACI,aAAa;IACb,8BAA8B;IAC9B,mBAAmB;IACnB,eAAe;AACnB;;AAEA;IACI,iBAAiB;IACjB,iBAAiB;IACjB,qBAAqB;AACzB;;AAEA;IACI,aAAa;IACb,SAAS;IACT,aAAa;IACb,eAAe;IACf,eAAe;AACnB;;AAEA;IACI,qBAAqB;IACrB,kBAAkB;IAClB,gBAAgB;IAChB,qBAAqB;IACrB,eAAe;AACnB;AACA;IACI,YAAY;IACZ,cAAc;AAClB;;AAEA;IACI,iBAAiB;IACjB,cAAc;IACd,iBAAiB;AACrB;;AAEA,WAAW;AACX;IACI,iBAAiB;IACjB,qCAAqC;IACrC;aACS;IACT,WAAW;IACX,aAAa;AACjB;;AAEA;IACI,aAAa;IACb,8BAA8B;IAC9B,mBAAmB;IACnB,eAAe;AACnB;;AAEA;IACI,iBAAiB;IACjB,iBAAiB;IACjB,qBAAqB;AACzB;;AAEA;IACI,aAAa;IACb,SAAS;AACb;;AAEA;IACI,qBAAqB;IACrB,kBAAkB;IAClB,gBAAgB;IAChB,qBAAqB;AACzB;AACA;IACI,YAAY;AAChB;;AAEA,WAAW;AACX;IACI,mBAAmB;IACnB,cAAc;IACd,oBAAoB;AACxB;;AAEA;IACI,aAAa;IACb,2DAA2D;IAC3D,SAAS;IACT,mBAAmB;AACvB;;AAEA;IACI,WAAW;IACX,mBAAmB;IACnB,iBAAiB;AACrB;;AAEA;IACI,gBAAgB;IAChB,UAAU;AACd;;AAEA;IACI,qBAAqB;AACzB;;AAEA;IACI,cAAc;IACd,qBAAqB;IACrB,2BAA2B;AAC/B;;AAEA;IACI,WAAW;IACX,0BAA0B;AAC9B;;AAEA;IACI,6BAA6B;IAC7B,iBAAiB;IACjB,kBAAkB;IAClB,iBAAiB;AACrB;;AAEA;IACI,iBAAiB;AACrB;;AAEA;IACI;QACI,0BAA0B;QAC1B,kBAAkB;IACtB;AACJ;;AAEA;IACI;QACI,aAAa;IACjB;AACJ,C;ACvJA;IACI,uBAAuB;AAC3B;;AAEA;IACI,WAAW;AACf,C","sources":["webpack://app/./static/css/sections/core.css","webpack://app/./static/css/pages/core/admin_home.css"],"sourcesContent":["\n/* Home page\n*/\nheader {\n background: white;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n /* position: fixed;\n top: 0; */\n width: 100%;\n z-index: 1000;\n}\n\n.navbar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1rem 0;\n}\n\n.logo {\n font-size: 1.5rem;\n font-weight: bold;\n color: var(--primary);\n}\n\n.nav-links {\n display: flex;\n gap: 2rem;\n display: flex;\n flex-wrap: wrap;\n max-width: 70vw;\n}\n\n.nav-links a {\n text-decoration: none;\n color: var(--text);\n font-weight: 500;\n align-content: center;\n font-size: 1rem;\n}\n.nav-links a.button {\n color: white;\n margin: 0 auto;\n}\n\n.container {\n max-width: 1200px;\n margin: 0 auto;\n padding: 0 1.5rem;\n}\n\n/* Header */\nheader {\n background: white;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n /* position: fixed;\n top: 0; */\n width: 100%;\n z-index: 1000;\n}\n\n.navbar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1rem 0;\n}\n\n.logo {\n font-size: 1.5rem;\n font-weight: bold;\n color: var(--primary);\n}\n\n.nav-links {\n display: flex;\n gap: 2rem;\n}\n\n.nav-links a {\n text-decoration: none;\n color: var(--text);\n font-weight: 500;\n align-content: center;\n}\n.nav-links a.button {\n color: white;\n}\n\n/* Footer */\n.footer {\n background: #1f2937;\n color: #f3f4f6;\n padding: 4rem 0 2rem;\n}\n\n.footer-content {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 2rem;\n margin-bottom: 2rem;\n}\n\n.footer-section h3 {\n color: #fff;\n margin-bottom: 1rem;\n font-size: 1.2rem;\n}\n\n.footer-section ul {\n list-style: none;\n padding: 0;\n}\n\n.footer-section ul li {\n margin-bottom: 0.5rem;\n}\n\n.footer-section a {\n color: #f3f4f6;\n text-decoration: none;\n transition: color 0.3s ease;\n}\n\n.footer-section a:hover {\n color: #fff;\n text-decoration: underline;\n}\n\n.footer-bottom {\n border-top: 1px solid #374151;\n padding-top: 2rem;\n text-align: center;\n font-size: 0.9rem;\n}\n\n.footer-bottom a {\n color: aquamarine;\n}\n\n@media (max-width: 768px) {\n .footer-content {\n grid-template-columns: 1fr;\n text-align: center;\n }\n}\n\n@media (max-width: 450px) {\n .nav-links {\n display: none;\n }\n}","#pageBody > .card:first-of-type {\n width: min(80vw, 500px);\n}\n\n.container.row {\n width: auto;\n}"],"names":[],"sourceRoot":""}

289
static/dist/css/core_contact.bundle.css vendored Normal file
View File

@@ -0,0 +1,289 @@
/* Home page
*/
header {
background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
/* position: fixed;
top: 0; */
width: 100%;
z-index: 1000;
}
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 0;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
color: var(--primary);
}
.nav-links {
display: flex;
gap: 2rem;
display: flex;
flex-wrap: wrap;
max-width: 70vw;
}
.nav-links a {
text-decoration: none;
color: var(--text);
font-weight: 500;
align-content: center;
font-size: 1rem;
}
.nav-links a.button {
color: white;
margin: 0 auto;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 1.5rem;
}
/* Header */
header {
background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
/* position: fixed;
top: 0; */
width: 100%;
z-index: 1000;
}
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 0;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
color: var(--primary);
}
.nav-links {
display: flex;
gap: 2rem;
}
.nav-links a {
text-decoration: none;
color: var(--text);
font-weight: 500;
align-content: center;
}
.nav-links a.button {
color: white;
}
/* Footer */
.footer {
background: #1f2937;
color: #f3f4f6;
padding: 4rem 0 2rem;
}
.footer-content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 2rem;
margin-bottom: 2rem;
}
.footer-section h3 {
color: #fff;
margin-bottom: 1rem;
font-size: 1.2rem;
}
.footer-section ul {
list-style: none;
padding: 0;
}
.footer-section ul li {
margin-bottom: 0.5rem;
}
.footer-section a {
color: #f3f4f6;
text-decoration: none;
transition: color 0.3s ease;
}
.footer-section a:hover {
color: #fff;
text-decoration: underline;
}
.footer-bottom {
border-top: 1px solid #374151;
padding-top: 2rem;
text-align: center;
font-size: 0.9rem;
}
.footer-bottom a {
color: aquamarine;
}
@media (max-width: 768px) {
.footer-content {
grid-template-columns: 1fr;
text-align: center;
}
}
@media (max-width: 450px) {
.nav-links {
display: none;
}
}
.contact-section {
padding: 2rem 2rem 4rem;
}
.contact-section h1 {
margin: 1rem auto;
}
.contact-section p {
margin: 0.5rem auto;
}
.contact-form {
max-width: 60vw;
width: fit-content;
margin: 0 auto;
background: #fff;
padding: 2rem;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.contact-form textarea {
max-width: 40vw;
}
.form-grid {
display: grid;
grid-template-columns: 200px 1fr;
gap: 1.5rem;
margin-bottom: 1rem;
}
.form-label {
padding-top: 0.5rem;
font-weight: 500;
}
.form-input {
width: 100%;
padding: 0.5rem;
border: 1px solid #d1d5db;
border-radius: 4px;
font-size: 1rem;
}
textarea.form-input {
min-height: 120px;
}
.marketing-consent input {
display: inline-block;
margin-left: 20%;
margin-bottom: 1.25rem;
}
.container.captcha > div:first-child > label:first-child {
display: flex;
justify-content: center;
width: fit-content;
text-align: center;
margin: 0 auto;
}
.container.captcha > p:last-child{
font-size: 0.9rem;
margin: 1vh 0;
}
.container.captcha .altcha-main {
padding-left: 1rem;
padding-top: 0.75rem;
padding-bottom: 0;
}
.container.captcha .altcha-main > :last-child {
display: none;
}
.container.captcha .altcha,
altcha-widget > div:first-child,
.container.captcha > div > .altcha-widget > div {
width: fit-content;
display: flex;
margin-left: auto;
margin-right: auto;
}
input[type="submit"] {
margin-left: 40%;
padding: 0.75rem 1.5rem;
background: #2563eb;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 1rem;
}
input[type="submit"]:hover {
background: #1d4ed8;
}
.data-notice {
margin-top: 3rem;
padding: 1.5rem;
background: #f3f4f6;
border-radius: 4px;
font-size: 0.95rem;
}
.data-notice h3 {
margin-bottom: 1rem;
font-size: 1.1rem;
}
.data-notice ul li {
list-style-position: inside;
}
@media (max-width: 768px) {
.contact-form {
max-width: 80vw;
}
.contact-form textarea {
max-width: 60vw;
}
.form-grid {
grid-template-columns: 1fr;
gap: 0.5rem;
}
.form-label {
padding-top: 0;
}
.submit-button {
margin-left: 0;
width: 100%;
}
}
@media (max-width: 400px) {
}
/*# sourceMappingURL=core_contact.bundle.css.map*/

File diff suppressed because one or more lines are too long

View File

@@ -1,66 +1,197 @@
/* Hero Section */ /* Home page
.home-hero { */
padding: 8rem 0 4rem; header {
align-self: center;
margin-left: auto;
margin-right: auto;
}
.hero-content {
max-width: 600px;
}
.home-hero h2 {
font-size: 24px;
line-height: 1.2;
margin-bottom: 1.5rem;
color: var(--colour-text);
margin-left: auto;
margin-right: auto;
}
.home-hero a {
font-size: 1.25rem;
margin-bottom: 2rem;
color: var(--colour-primary);
cursor: pointer;
margin-left: auto;
margin-right: auto;
}
/* Services Section */
.services {
padding: 6rem 0;
background: white; background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
/* position: fixed;
top: 0; */
width: 100%;
z-index: 1000;
} }
.services-grid { .navbar {
display: grid; display: flex;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); justify-content: space-between;
align-items: center;
padding: 1rem 0;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
color: var(--primary);
}
.nav-links {
display: flex;
gap: 2rem; gap: 2rem;
margin-top: 3rem; display: flex;
flex-wrap: wrap;
max-width: 70vw;
} }
.service-card { .nav-links a {
text-decoration: none;
color: var(--text);
font-weight: 500;
align-content: center;
font-size: 1rem;
}
.nav-links a.button {
color: white;
margin: 0 auto;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 1.5rem;
}
/* Header */
header {
background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
/* position: fixed;
top: 0; */
width: 100%;
z-index: 1000;
}
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 0;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
color: var(--primary);
}
.nav-links {
display: flex;
gap: 2rem;
}
.nav-links a {
text-decoration: none;
color: var(--text);
font-weight: 500;
align-content: center;
}
.nav-links a.button {
color: white;
}
/* Footer */
.footer {
background: #1f2937;
color: #f3f4f6;
padding: 4rem 0 2rem;
}
.footer-content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 2rem;
margin-bottom: 2rem;
}
.footer-section h3 {
color: #fff;
margin-bottom: 1rem;
font-size: 1.2rem;
}
.footer-section ul {
list-style: none;
padding: 0;
}
.footer-section ul li {
margin-bottom: 0.5rem;
}
.footer-section a {
color: #f3f4f6;
text-decoration: none;
transition: color 0.3s ease;
}
.footer-section a:hover {
color: #fff;
text-decoration: underline;
}
.footer-bottom {
border-top: 1px solid #374151;
padding-top: 2rem;
text-align: center;
font-size: 0.9rem;
}
.footer-bottom a {
color: aquamarine;
}
@media (max-width: 768px) {
.footer-content {
grid-template-columns: 1fr;
text-align: center;
}
}
@media (max-width: 450px) {
.nav-links {
display: none;
}
}
/* Common */
p {
width: 100%;
font-size: 16px;
}
p.section-title,
p.section-subtitle {
margin: 0 auto;
}
.section-subtitle {
font-size: 18px;
}
ul li {
font-size: 16px;
}
section.problem,
section.benefits,
section.features,
section.faq {
padding: 6rem 0;
background: var(--colour-text-background);
}
section.problem .card.problem,
section.benefits .card.benefits,
section.features .card.features,
section.faq .card.faq {
padding: 2rem; padding: 2rem;
background: var(--light); background: var(--colour-page-background);
border-radius: 8px; border-radius: 8px;
transition: transform 0.3s ease; transition: transform 0.3s ease;
display: block;
} }
.service-card:hover { section.solution,
transform: translateY(-5px); section.social-proof {
}
/* Testimonial Section */
.testimonial {
padding: 6rem 0; padding: 6rem 0;
background: var(--light); background: var(--colour-page-background-1);
} }
section.solution .card.solution,
.testimonial-card { section.social-proof .card.social-proof {
background: white; background: var(--colour-text-background);
padding: 2rem; padding: 2rem;
border-radius: 8px; border-radius: 8px;
max-width: 800px; max-width: 800px;
@@ -68,14 +199,56 @@
box-shadow: 0 4px 6px rgba(0,0,0,0.1); box-shadow: 0 4px 6px rgba(0,0,0,0.1);
} }
/* Pricing Section */ /* Hero Section */
.pricing { .hero {
padding: 8rem 0 4rem;
background: linear-gradient(45deg, var(--colour-page-background-1), var(--colour-page-background-2)); /* linear-gradient(45deg, #f8fafc, #eff6ff); */
}
.hero-content {
max-width: 600px;
}
.hero h1 {
font-size: 3rem;
line-height: 1.2;
margin-bottom: 1.5rem;
color: var(--colour-text);
}
.hero p {
font-size: 1.25rem;
margin-bottom: 2rem;
color: var(--colour-secondary);
}
/* Problem Section */
/*
section.problem .problem.card:hover {
transform: translateY(-5px);
}
*/
/* Solution Section */
/* Benefits Section */
section.benefits .section-subtitle {
font-size: 18px;
font-weight: bold;
}
/* Social Proof Section * /
section.social-proof {
padding: 6rem 0; padding: 6rem 0;
background: white; background: white;
} }
.pricing-card { section.social-proof .card.social-proof {
background: var(--light); background: var(--colour-page-background);
padding: 2rem; padding: 2rem;
border-radius: 8px; border-radius: 8px;
text-align: center; text-align: center;
@@ -83,21 +256,63 @@
margin: 3rem auto 0; margin: 3rem auto 0;
} }
.price { section.social-proof ul {
font-size: 2.5rem; list-style: none;
color: var(--primary); margin: 0;
font-weight: bold; }
margin: 1rem 0; * /
section.social-proof .section-subtitle {
font-size: 16px;
}
*/
section.social-proof ul li {
font-size: 14px;
}
/* Early Access Section * /
section.early-access {
padding: 6rem 0;
background: white;
}
section.early-access .card.early-access {
background: var(--colour-page-background);
padding: 2rem;
border-radius: 8px;
text-align: center;
max-width: 400px;
margin: 3rem auto 0;
}
section.early-access ul {
list-style: none;
margin: 0;
}
section.early-access a.button {
margin: 0.25rem;
}
*/
/* Features section */
section.features .button {
margin-top: 0;
} }
/* CTA Section */ /* CTA Section */
.cta { .cta-1,
.cta-2 {
padding: 6rem 0; padding: 6rem 0;
background: var(--primary); background: var(--colour-primary);
color: white; color: white;
text-align: center; text-align: center;
} }
/* FAQs * /
section.faq .button {
margin-bottom: 0.25rem;
}
*/
/* Animations */ /* Animations */
/* Fallback styles to ensure content is visible without JS */ /* Fallback styles to ensure content is visible without JS */
@@ -132,4 +347,39 @@
.delay-3 { animation-delay: 0.3s; } .delay-3 { animation-delay: 0.3s; }
.delay-4 { animation-delay: 0.4s; } .delay-4 { animation-delay: 0.4s; }
/* Buttons */
.button {
display: inline-block;
padding: 0.75rem 1.5rem;
border-radius: 6px;
text-decoration: none;
font-weight: 500;
transition: all 0.3s ease;
width: fit-content;
margin: 0.75rem;
font-size: 18px;
}
.button-primary {
background: var(--colour-primary);
color: white;
}
.button-primary:hover {
background: var(--colour-secondary);
}
.button-light {
background: white;
color: var(--colour-primary);
}
.button-light:hover {
background: var(--colour-page-background);
}
.logo:hover{
cursor: pointer;
}
/*# sourceMappingURL=core_home.bundle.css.map*/ /*# sourceMappingURL=core_home.bundle.css.map*/

File diff suppressed because one or more lines are too long

View File

@@ -1,38 +1,4 @@
.img-product {
max-width: 20vh;
max-height: 20vh;
border-radius: 3vh;
justify-self: left;
}
.img-thumbnail {
max-width: 10vh;
max-height: 10vh;
border-radius: 3vh;
justify-self: left;
}
.buttonAddToBasket {
background-color: var(--colour-page-background);
border-color: var(--colour-primary);
}
#buttonCheckout, .buttonBuyNow {
background-color: var(--colour-page-background);
/* color: var(--c_purple_dark); */
border-color: var(--colour-primary);
}
.button-increment, .button-decrement {
border: 2px solid darkgrey;
background-color: lightgray;
margin: 1vh 1vh;
width: 2.5vh;
height: 2.5vh;
border-radius: 1.25vh;
font-size: 2vh;
}
.container-input > input { .container-input > input {
padding: 0vh 1vh; padding: 0vh 1vh;
@@ -55,6 +21,59 @@
#pageBody {
/* height: 69vh !important; */
max-height: 79vh;
padding: 0 5vw;
margin: 0;
border: 0;
align-content: center;
justify-content: flex-start;
display: flex;
flex-direction: column;
align-items: flex-start;
overflow-y: auto;
overflow-x: hidden;
position: absolute;
width: 90vw;
color: var(--colour-text);
}
/* Footer */
.footer {
padding: 1vh 1vw;
text-align: center;
margin: 0;
max-height: 5vh;
overflow-y: auto;
background-color: var(--colour-accent);
position: absolute;
bottom: 0;
width: 98vw;
}
@media screen and (max-width: 400px) {
.footer {
max-height: 8vh;
padding: 0 2vw;
font-size: 10px;
width: 96vw;
max-width: 96vw;
}
.footer > h4 {
font-size: 10px;
}
.footer > h5 {
font-size: 9px;
}
}
.footer > h4, h5 {
padding: 0;
margin: 0;
}
.container.save.button-cancel { .container.save.button-cancel {
position: fixed; position: fixed;
@@ -117,8 +136,8 @@ table.table-main.assessment_command_modality_link tbody tr td.notes {
table.table-main.assessment_command_modality_link thead tr th.assessment_response, table.table-main.assessment_command_modality_link thead tr th.assessment_response,
table.table-main.assessment_command_modality_link tbody tr td.assessment_response { table.table-main.assessment_command_modality_link tbody tr td.assessment_response {
max-width: 40vh; max-width: 43vh;
min-width: 40vh; min-width: 43vh;
} }
/*# sourceMappingURL=dog_assessment.bundle.css.map*/ /*# sourceMappingURL=dog_assessment.bundle.css.map*/

View File

@@ -1 +1 @@
{"version":3,"file":"css/dog_assessment.bundle.css","mappings":";AACA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,+CAA+C;IAC/C,mCAAmC;AACvC;;AAEA;IACI,+CAA+C;IAC/C,iCAAiC;IACjC,mCAAmC;AACvC;;AAEA;IACI,0BAA0B;IAC1B,2BAA2B;IAC3B,eAAe;IACf,YAAY;IACZ,aAAa;IACb,qBAAqB;IACrB,cAAc;AAClB;;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;;;;;ACnDf;IACI,eAAe;IACf,SAAS;IACT,WAAW;AACf;;;AAGA;;;;;;;;IAQI,cAAc;IACd,cAAc;AAClB;;AAEA;;IAEI,eAAe;IACf,eAAe;AACnB;;AAEA;;IAEI,eAAe;IACf,eAAe;AACnB;;AAEA;;IAEI,cAAc;IACd,cAAc;AAClB;AACA;;IAEI,eAAe;IACf,gBAAgB;AACpB;AACA;;;;;;;;IAQI,cAAc;IACd,cAAc;AAClB;AACA;;IAEI,eAAe;IACf,eAAe;AACnB;;;AAGA;;IAEI,eAAe;IACf,eAAe;AACnB,C","sources":["webpack://app/./static/css/sections/dog.css","webpack://app/./static/css/pages/dog/assessment.css"],"sourcesContent":["\n.img-product {\n max-width: 20vh;\n max-height: 20vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.img-thumbnail {\n max-width: 10vh;\n max-height: 10vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.buttonAddToBasket {\n background-color: var(--colour-page-background);\n border-color: var(--colour-primary);\n}\n\n#buttonCheckout, .buttonBuyNow {\n background-color: var(--colour-page-background);\n /* color: var(--c_purple_dark); */\n border-color: var(--colour-primary);\n}\n\n.button-increment, .button-decrement {\n border: 2px solid darkgrey;\n background-color: lightgray;\n margin: 1vh 1vh;\n width: 2.5vh;\n height: 2.5vh;\n border-radius: 1.25vh;\n font-size: 2vh;\n}\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n","\n\n.container.save.button-cancel {\n position: fixed;\n top: 10vh;\n right: 10vh;\n}\n\n\ntable.table-main.assessment thead tr th.active,\ntable.table-main.assessment tbody tr td.active,\ntable.table-main.distraction thead tr th.active,\ntable.table-main.distraction tbody tr td.active,\ntable.table-main.assessment_command_modality_link thead tr th.active,\ntable.table-main.assessment_command_modality_link tbody tr td.active,\ntable.table-main.assessment_response thead tr th.active,\ntable.table-main.assessment_response tbody tr td.active {\n max-width: 6vh;\n min-width: 6vh;\n}\n\ntable.table-main.assessment thead tr th,\ntable.table-main.assessment tbody tr td {\n max-width: 15vh;\n min-width: 15vh;\n}\n\ntable.table-main.distraction thead tr th,\ntable.table-main.distraction tbody tr td {\n max-width: 12vh;\n min-width: 12vh;\n}\n\ntable.table-main.assessment_command_modality_link thead tr th,\ntable.table-main.assessment_command_modality_link tbody tr td {\n max-width: 6vh;\n min-width: 6vh;\n}\ntable.table-main.assessment_command_modality_link tbody tr td.ddl-preview div, \ntable.table-main.assessment_command_modality_link tbody tr td.ddl-preview select {\n padding-left: 0;\n padding-right: 0;\n}\ntable.table-main.assessment_command_modality_link thead tr th.is-in-hearing-range-of-handler,\ntable.table-main.assessment_command_modality_link tbody tr td.is-in-hearing-range-of-handler,\ntable.table-main.assessment_command_modality_link thead tr th.is-in-scent-range-of-handler,\ntable.table-main.assessment_command_modality_link tbody tr td.is-in-scent-range-of-handler,\ntable.table-main.assessment_command_modality_link thead tr th.is-in-sight-of-handler,\ntable.table-main.assessment_command_modality_link tbody tr td.is-in-sight-of-handler,\ntable.table-main.assessment_command_modality_link thead tr th.is-on-lead,\ntable.table-main.assessment_command_modality_link tbody tr td.is-on-lead {\n max-width: 4vh;\n min-width: 4vh;\n}\ntable.table-main.assessment_command_modality_link thead tr th.notes,\ntable.table-main.assessment_command_modality_link tbody tr td.notes {\n max-width: 12vh;\n min-width: 12vh;\n}\n\n\ntable.table-main.assessment_command_modality_link thead tr th.assessment_response,\ntable.table-main.assessment_command_modality_link tbody tr td.assessment_response {\n max-width: 40vh;\n min-width: 40vh;\n}"],"names":[],"sourceRoot":""} {"version":3,"file":"css/dog_assessment.bundle.css","mappings":";;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;;;;AAIf;IACI,6BAA6B;IAC7B,gBAAgB;IAChB,cAAc;IACd,SAAS;IACT,SAAS;IACT,qBAAqB;IACrB,2BAA2B;IAC3B,aAAa;IACb,sBAAsB;IACtB,uBAAuB;IACvB,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;IAClB,WAAW;IACX,yBAAyB;AAC7B;;;AAGA,WAAW;AACX;IACI,gBAAgB;IAChB,kBAAkB;IAClB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,sCAAsC;IACtC,kBAAkB;IAClB,SAAS;IACT,WAAW;AACf;;AAEA;IACI;QACI,eAAe;QACf,cAAc;QACd,eAAe;QACf,WAAW;QACX,eAAe;IACnB;IACA;QACI,eAAe;IACnB;IACA;QACI,cAAc;IAClB;AACJ;;AAEA;IACI,UAAU;IACV,SAAS;AACb,C;;;ACxEA;IACI,eAAe;IACf,SAAS;IACT,WAAW;AACf;;;AAGA;;;;;;;;IAQI,cAAc;IACd,cAAc;AAClB;;AAEA;;IAEI,eAAe;IACf,eAAe;AACnB;;AAEA;;IAEI,eAAe;IACf,eAAe;AACnB;;AAEA;;IAEI,cAAc;IACd,cAAc;AAClB;AACA;;IAEI,eAAe;IACf,gBAAgB;AACpB;AACA;;;;;;;;IAQI,cAAc;IACd,cAAc;AAClB;AACA;;IAEI,eAAe;IACf,eAAe;AACnB;;;AAGA;;IAEI,eAAe;IACf,eAAe;AACnB,C","sources":["webpack://app/./static/css/sections/dog.css","webpack://app/./static/css/pages/dog/assessment.css"],"sourcesContent":["\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n\n\n#pageBody {\n /* height: 69vh !important; */\n max-height: 79vh;\n padding: 0 5vw;\n margin: 0;\n border: 0;\n align-content: center;\n justify-content: flex-start;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n overflow-x: hidden;\n position: absolute;\n width: 90vw;\n color: var(--colour-text);\n}\n\n\n/* Footer */\n.footer {\n padding: 1vh 1vw;\n text-align: center;\n margin: 0;\n max-height: 5vh;\n overflow-y: auto;\n background-color: var(--colour-accent);\n position: absolute;\n bottom: 0;\n width: 98vw;\n}\n\n@media screen and (max-width: 400px) {\n .footer {\n max-height: 8vh;\n padding: 0 2vw;\n font-size: 10px; \n width: 96vw;\n max-width: 96vw;\n }\n .footer > h4 {\n font-size: 10px;\n }\n .footer > h5 {\n font-size: 9px;\n }\n}\n\n.footer > h4, h5 {\n padding: 0;\n margin: 0;\n}","\n\n.container.save.button-cancel {\n position: fixed;\n top: 10vh;\n right: 10vh;\n}\n\n\ntable.table-main.assessment thead tr th.active,\ntable.table-main.assessment tbody tr td.active,\ntable.table-main.distraction thead tr th.active,\ntable.table-main.distraction tbody tr td.active,\ntable.table-main.assessment_command_modality_link thead tr th.active,\ntable.table-main.assessment_command_modality_link tbody tr td.active,\ntable.table-main.assessment_response thead tr th.active,\ntable.table-main.assessment_response tbody tr td.active {\n max-width: 6vh;\n min-width: 6vh;\n}\n\ntable.table-main.assessment thead tr th,\ntable.table-main.assessment tbody tr td {\n max-width: 15vh;\n min-width: 15vh;\n}\n\ntable.table-main.distraction thead tr th,\ntable.table-main.distraction tbody tr td {\n max-width: 12vh;\n min-width: 12vh;\n}\n\ntable.table-main.assessment_command_modality_link thead tr th,\ntable.table-main.assessment_command_modality_link tbody tr td {\n max-width: 6vh;\n min-width: 6vh;\n}\ntable.table-main.assessment_command_modality_link tbody tr td.ddl-preview div, \ntable.table-main.assessment_command_modality_link tbody tr td.ddl-preview select {\n padding-left: 0;\n padding-right: 0;\n}\ntable.table-main.assessment_command_modality_link thead tr th.is-in-hearing-range-of-handler,\ntable.table-main.assessment_command_modality_link tbody tr td.is-in-hearing-range-of-handler,\ntable.table-main.assessment_command_modality_link thead tr th.is-in-scent-range-of-handler,\ntable.table-main.assessment_command_modality_link tbody tr td.is-in-scent-range-of-handler,\ntable.table-main.assessment_command_modality_link thead tr th.is-in-sight-of-handler,\ntable.table-main.assessment_command_modality_link tbody tr td.is-in-sight-of-handler,\ntable.table-main.assessment_command_modality_link thead tr th.is-on-lead,\ntable.table-main.assessment_command_modality_link tbody tr td.is-on-lead {\n max-width: 4vh;\n min-width: 4vh;\n}\ntable.table-main.assessment_command_modality_link thead tr th.notes,\ntable.table-main.assessment_command_modality_link tbody tr td.notes {\n max-width: 12vh;\n min-width: 12vh;\n}\n\n\ntable.table-main.assessment_command_modality_link thead tr th.assessment_response,\ntable.table-main.assessment_command_modality_link tbody tr td.assessment_response {\n max-width: 43vh;\n min-width: 43vh;\n}"],"names":[],"sourceRoot":""}

View File

@@ -1,38 +1,4 @@
.img-product {
max-width: 20vh;
max-height: 20vh;
border-radius: 3vh;
justify-self: left;
}
.img-thumbnail {
max-width: 10vh;
max-height: 10vh;
border-radius: 3vh;
justify-self: left;
}
.buttonAddToBasket {
background-color: var(--colour-page-background);
border-color: var(--colour-primary);
}
#buttonCheckout, .buttonBuyNow {
background-color: var(--colour-page-background);
/* color: var(--c_purple_dark); */
border-color: var(--colour-primary);
}
.button-increment, .button-decrement {
border: 2px solid darkgrey;
background-color: lightgray;
margin: 1vh 1vh;
width: 2.5vh;
height: 2.5vh;
border-radius: 1.25vh;
font-size: 2vh;
}
.container-input > input { .container-input > input {
padding: 0vh 1vh; padding: 0vh 1vh;
@@ -55,5 +21,58 @@
#pageBody {
/* height: 69vh !important; */
max-height: 79vh;
padding: 0 5vw;
margin: 0;
border: 0;
align-content: center;
justify-content: flex-start;
display: flex;
flex-direction: column;
align-items: flex-start;
overflow-y: auto;
overflow-x: hidden;
position: absolute;
width: 90vw;
color: var(--colour-text);
}
/* Footer */
.footer {
padding: 1vh 1vw;
text-align: center;
margin: 0;
max-height: 5vh;
overflow-y: auto;
background-color: var(--colour-accent);
position: absolute;
bottom: 0;
width: 98vw;
}
@media screen and (max-width: 400px) {
.footer {
max-height: 8vh;
padding: 0 2vw;
font-size: 10px;
width: 96vw;
max-width: 96vw;
}
.footer > h4 {
font-size: 10px;
}
.footer > h5 {
font-size: 9px;
}
}
.footer > h4, h5 {
padding: 0;
margin: 0;
}
/*# sourceMappingURL=dog_assessments.bundle.css.map*/ /*# sourceMappingURL=dog_assessments.bundle.css.map*/

View File

@@ -1 +1 @@
{"version":3,"file":"css/dog_assessments.bundle.css","mappings":";AACA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,+CAA+C;IAC/C,mCAAmC;AACvC;;AAEA;IACI,+CAA+C;IAC/C,iCAAiC;IACjC,mCAAmC;AACvC;;AAEA;IACI,0BAA0B;IAC1B,2BAA2B;IAC3B,eAAe;IACf,YAAY;IACZ,aAAa;IACb,qBAAqB;IACrB,cAAc;AAClB;;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe","sources":["webpack://app/./static/css/sections/dog.css"],"sourcesContent":["\n.img-product {\n max-width: 20vh;\n max-height: 20vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.img-thumbnail {\n max-width: 10vh;\n max-height: 10vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.buttonAddToBasket {\n background-color: var(--colour-page-background);\n border-color: var(--colour-primary);\n}\n\n#buttonCheckout, .buttonBuyNow {\n background-color: var(--colour-page-background);\n /* color: var(--c_purple_dark); */\n border-color: var(--colour-primary);\n}\n\n.button-increment, .button-decrement {\n border: 2px solid darkgrey;\n background-color: lightgray;\n margin: 1vh 1vh;\n width: 2.5vh;\n height: 2.5vh;\n border-radius: 1.25vh;\n font-size: 2vh;\n}\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n"],"names":[],"sourceRoot":""} {"version":3,"file":"css/dog_assessments.bundle.css","mappings":";;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;;;;AAIf;IACI,6BAA6B;IAC7B,gBAAgB;IAChB,cAAc;IACd,SAAS;IACT,SAAS;IACT,qBAAqB;IACrB,2BAA2B;IAC3B,aAAa;IACb,sBAAsB;IACtB,uBAAuB;IACvB,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;IAClB,WAAW;IACX,yBAAyB;AAC7B;;;AAGA,WAAW;AACX;IACI,gBAAgB;IAChB,kBAAkB;IAClB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,sCAAsC;IACtC,kBAAkB;IAClB,SAAS;IACT,WAAW;AACf;;AAEA;IACI;QACI,eAAe;QACf,cAAc;QACd,eAAe;QACf,WAAW;QACX,eAAe;IACnB;IACA;QACI,eAAe;IACnB;IACA;QACI,cAAc;IAClB;AACJ;;AAEA;IACI,UAAU;IACV,SAAS;AACb,C","sources":["webpack://app/./static/css/sections/dog.css"],"sourcesContent":["\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n\n\n#pageBody {\n /* height: 69vh !important; */\n max-height: 79vh;\n padding: 0 5vw;\n margin: 0;\n border: 0;\n align-content: center;\n justify-content: flex-start;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n overflow-x: hidden;\n position: absolute;\n width: 90vw;\n color: var(--colour-text);\n}\n\n\n/* Footer */\n.footer {\n padding: 1vh 1vw;\n text-align: center;\n margin: 0;\n max-height: 5vh;\n overflow-y: auto;\n background-color: var(--colour-accent);\n position: absolute;\n bottom: 0;\n width: 98vw;\n}\n\n@media screen and (max-width: 400px) {\n .footer {\n max-height: 8vh;\n padding: 0 2vw;\n font-size: 10px; \n width: 96vw;\n max-width: 96vw;\n }\n .footer > h4 {\n font-size: 10px;\n }\n .footer > h5 {\n font-size: 9px;\n }\n}\n\n.footer > h4, h5 {\n padding: 0;\n margin: 0;\n}"],"names":[],"sourceRoot":""}

View File

@@ -1,38 +1,4 @@
.img-product {
max-width: 20vh;
max-height: 20vh;
border-radius: 3vh;
justify-self: left;
}
.img-thumbnail {
max-width: 10vh;
max-height: 10vh;
border-radius: 3vh;
justify-self: left;
}
.buttonAddToBasket {
background-color: var(--colour-page-background);
border-color: var(--colour-primary);
}
#buttonCheckout, .buttonBuyNow {
background-color: var(--colour-page-background);
/* color: var(--c_purple_dark); */
border-color: var(--colour-primary);
}
.button-increment, .button-decrement {
border: 2px solid darkgrey;
background-color: lightgray;
margin: 1vh 1vh;
width: 2.5vh;
height: 2.5vh;
border-radius: 1.25vh;
font-size: 2vh;
}
.container-input > input { .container-input > input {
padding: 0vh 1vh; padding: 0vh 1vh;
@@ -55,6 +21,59 @@
#pageBody {
/* height: 69vh !important; */
max-height: 79vh;
padding: 0 5vw;
margin: 0;
border: 0;
align-content: center;
justify-content: flex-start;
display: flex;
flex-direction: column;
align-items: flex-start;
overflow-y: auto;
overflow-x: hidden;
position: absolute;
width: 90vw;
color: var(--colour-text);
}
/* Footer */
.footer {
padding: 1vh 1vw;
text-align: center;
margin: 0;
max-height: 5vh;
overflow-y: auto;
background-color: var(--colour-accent);
position: absolute;
bottom: 0;
width: 98vw;
}
@media screen and (max-width: 400px) {
.footer {
max-height: 8vh;
padding: 0 2vw;
font-size: 10px;
width: 96vw;
max-width: 96vw;
}
.footer > h4 {
font-size: 10px;
}
.footer > h5 {
font-size: 9px;
}
}
.footer > h4, h5 {
padding: 0;
margin: 0;
}
#tableMain tbody > div { #tableMain tbody > div {
width: 49vh; width: 49vh;

View File

@@ -1 +1 @@
{"version":3,"file":"css/dog_button_icons.bundle.css","mappings":";AACA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,+CAA+C;IAC/C,mCAAmC;AACvC;;AAEA;IACI,+CAA+C;IAC/C,iCAAiC;IACjC,mCAAmC;AACvC;;AAEA;IACI,0BAA0B;IAC1B,2BAA2B;IAC3B,eAAe;IACf,YAAY;IACZ,aAAa;IACb,qBAAqB;IACrB,cAAc;AAClB;;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;;;;;ACnDf;IACI,WAAW;AACf","sources":["webpack://app/./static/css/sections/dog.css","webpack://app/./static/css/pages/dog/button_icons.css"],"sourcesContent":["\n.img-product {\n max-width: 20vh;\n max-height: 20vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.img-thumbnail {\n max-width: 10vh;\n max-height: 10vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.buttonAddToBasket {\n background-color: var(--colour-page-background);\n border-color: var(--colour-primary);\n}\n\n#buttonCheckout, .buttonBuyNow {\n background-color: var(--colour-page-background);\n /* color: var(--c_purple_dark); */\n border-color: var(--colour-primary);\n}\n\n.button-increment, .button-decrement {\n border: 2px solid darkgrey;\n background-color: lightgray;\n margin: 1vh 1vh;\n width: 2.5vh;\n height: 2.5vh;\n border-radius: 1.25vh;\n font-size: 2vh;\n}\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n","\n\n#tableMain tbody > div {\n width: 49vh;\n}\n"],"names":[],"sourceRoot":""} {"version":3,"file":"css/dog_button_icons.bundle.css","mappings":";;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;;;;AAIf;IACI,6BAA6B;IAC7B,gBAAgB;IAChB,cAAc;IACd,SAAS;IACT,SAAS;IACT,qBAAqB;IACrB,2BAA2B;IAC3B,aAAa;IACb,sBAAsB;IACtB,uBAAuB;IACvB,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;IAClB,WAAW;IACX,yBAAyB;AAC7B;;;AAGA,WAAW;AACX;IACI,gBAAgB;IAChB,kBAAkB;IAClB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,sCAAsC;IACtC,kBAAkB;IAClB,SAAS;IACT,WAAW;AACf;;AAEA;IACI;QACI,eAAe;QACf,cAAc;QACd,eAAe;QACf,WAAW;QACX,eAAe;IACnB;IACA;QACI,eAAe;IACnB;IACA;QACI,cAAc;IAClB;AACJ;;AAEA;IACI,UAAU;IACV,SAAS;AACb,C;;;ACxEA;IACI,WAAW;AACf","sources":["webpack://app/./static/css/sections/dog.css","webpack://app/./static/css/pages/dog/button_icons.css"],"sourcesContent":["\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n\n\n#pageBody {\n /* height: 69vh !important; */\n max-height: 79vh;\n padding: 0 5vw;\n margin: 0;\n border: 0;\n align-content: center;\n justify-content: flex-start;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n overflow-x: hidden;\n position: absolute;\n width: 90vw;\n color: var(--colour-text);\n}\n\n\n/* Footer */\n.footer {\n padding: 1vh 1vw;\n text-align: center;\n margin: 0;\n max-height: 5vh;\n overflow-y: auto;\n background-color: var(--colour-accent);\n position: absolute;\n bottom: 0;\n width: 98vw;\n}\n\n@media screen and (max-width: 400px) {\n .footer {\n max-height: 8vh;\n padding: 0 2vw;\n font-size: 10px; \n width: 96vw;\n max-width: 96vw;\n }\n .footer > h4 {\n font-size: 10px;\n }\n .footer > h5 {\n font-size: 9px;\n }\n}\n\n.footer > h4, h5 {\n padding: 0;\n margin: 0;\n}","\n\n#tableMain tbody > div {\n width: 49vh;\n}\n"],"names":[],"sourceRoot":""}

View File

@@ -1,38 +1,4 @@
.img-product {
max-width: 20vh;
max-height: 20vh;
border-radius: 3vh;
justify-self: left;
}
.img-thumbnail {
max-width: 10vh;
max-height: 10vh;
border-radius: 3vh;
justify-self: left;
}
.buttonAddToBasket {
background-color: var(--colour-page-background);
border-color: var(--colour-primary);
}
#buttonCheckout, .buttonBuyNow {
background-color: var(--colour-page-background);
/* color: var(--c_purple_dark); */
border-color: var(--colour-primary);
}
.button-increment, .button-decrement {
border: 2px solid darkgrey;
background-color: lightgray;
margin: 1vh 1vh;
width: 2.5vh;
height: 2.5vh;
border-radius: 1.25vh;
font-size: 2vh;
}
.container-input > input { .container-input > input {
padding: 0vh 1vh; padding: 0vh 1vh;
@@ -55,6 +21,59 @@
#pageBody {
/* height: 69vh !important; */
max-height: 79vh;
padding: 0 5vw;
margin: 0;
border: 0;
align-content: center;
justify-content: flex-start;
display: flex;
flex-direction: column;
align-items: flex-start;
overflow-y: auto;
overflow-x: hidden;
position: absolute;
width: 90vw;
color: var(--colour-text);
}
/* Footer */
.footer {
padding: 1vh 1vw;
text-align: center;
margin: 0;
max-height: 5vh;
overflow-y: auto;
background-color: var(--colour-accent);
position: absolute;
bottom: 0;
width: 98vw;
}
@media screen and (max-width: 400px) {
.footer {
max-height: 8vh;
padding: 0 2vw;
font-size: 10px;
width: 96vw;
max-width: 96vw;
}
.footer > h4 {
font-size: 10px;
}
.footer > h5 {
font-size: 9px;
}
}
.footer > h4, h5 {
padding: 0;
margin: 0;
}
/* /*
#formFilters .container-input.filter.active_only { #formFilters .container-input.filter.active_only {
} }

View File

@@ -1 +1 @@
{"version":3,"file":"css/dog_command_button_links.bundle.css","mappings":";AACA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,+CAA+C;IAC/C,mCAAmC;AACvC;;AAEA;IACI,+CAA+C;IAC/C,iCAAiC;IACjC,mCAAmC;AACvC;;AAEA;IACI,0BAA0B;IAC1B,2BAA2B;IAC3B,eAAe;IACf,YAAY;IACZ,aAAa;IACb,qBAAqB;IACrB,cAAc;AAClB;;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;;;;ACpDf;;;CAGC;;;AAGD;IACI,YAAY;AAChB;;AAEA;;;;;;;CAOC;AACD;;;;;;IAMI,eAAe;IACf,eAAe;AACnB;;AAEA;;;;CAIC;;AAED;IACI;;QAEI,eAAe;QACf,eAAe;IACnB;AACJ","sources":["webpack://app/./static/css/sections/dog.css","webpack://app/./static/css/pages/dog/command_button_links.css"],"sourcesContent":["\n.img-product {\n max-width: 20vh;\n max-height: 20vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.img-thumbnail {\n max-width: 10vh;\n max-height: 10vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.buttonAddToBasket {\n background-color: var(--colour-page-background);\n border-color: var(--colour-primary);\n}\n\n#buttonCheckout, .buttonBuyNow {\n background-color: var(--colour-page-background);\n /* color: var(--c_purple_dark); */\n border-color: var(--colour-primary);\n}\n\n.button-increment, .button-decrement {\n border: 2px solid darkgrey;\n background-color: lightgray;\n margin: 1vh 1vh;\n width: 2.5vh;\n height: 2.5vh;\n border-radius: 1.25vh;\n font-size: 2vh;\n}\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n","\n/*\n#formFilters .container-input.filter.active_only {\n}\n*/\n\n\n#tableMain tbody > div {\n width: 113vh;\n}\n\n/*\n#tableMain tbody tr td table thead tr th.id_variation_type,\n#tableMain tbody tr td table tbody tr td.id_variation_type,\n#tableMain tbody tr td table thead tr th.id_variation, \n#tableMain tbody tr td table tbody tr td.id_variation {\n width: 47.5%;\n}\n*/\n#tableMain tbody tr td table thead tr th.button_shape, \n#tableMain tbody tr td table tbody tr td.button_shape,\n#tableMain tbody tr td table thead tr th.colour, \n#tableMain tbody tr td table tbody tr td.colour,\n#tableMain tbody tr td table thead tr th.button_icon, \n#tableMain tbody tr td table tbody tr td.button_icon {\n max-width: 12vh;\n max-width: 12vh;\n}\n\n/*\nselect.id_variation, select.id_variation_type {\n max-width: 40% !important;\n}\n*/\n\n@media screen and (max-width: 850px) {\n #formFilters input,\n #formFilters select {\n max-width: 12vh;\n min-width: 12vh;\n }\n}\n"],"names":[],"sourceRoot":""} {"version":3,"file":"css/dog_command_button_links.bundle.css","mappings":";;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;;;;AAIf;IACI,6BAA6B;IAC7B,gBAAgB;IAChB,cAAc;IACd,SAAS;IACT,SAAS;IACT,qBAAqB;IACrB,2BAA2B;IAC3B,aAAa;IACb,sBAAsB;IACtB,uBAAuB;IACvB,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;IAClB,WAAW;IACX,yBAAyB;AAC7B;;;AAGA,WAAW;AACX;IACI,gBAAgB;IAChB,kBAAkB;IAClB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,sCAAsC;IACtC,kBAAkB;IAClB,SAAS;IACT,WAAW;AACf;;AAEA;IACI;QACI,eAAe;QACf,cAAc;QACd,eAAe;QACf,WAAW;QACX,eAAe;IACnB;IACA;QACI,eAAe;IACnB;IACA;QACI,cAAc;IAClB;AACJ;;AAEA;IACI,UAAU;IACV,SAAS;AACb,C;;ACzEA;;;CAGC;;;AAGD;IACI,YAAY;AAChB;;AAEA;;;;;;;CAOC;AACD;;;;;;IAMI,eAAe;IACf,eAAe;AACnB;;AAEA;;;;CAIC;;AAED;IACI;;QAEI,eAAe;QACf,eAAe;IACnB;AACJ","sources":["webpack://app/./static/css/sections/dog.css","webpack://app/./static/css/pages/dog/command_button_links.css"],"sourcesContent":["\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n\n\n#pageBody {\n /* height: 69vh !important; */\n max-height: 79vh;\n padding: 0 5vw;\n margin: 0;\n border: 0;\n align-content: center;\n justify-content: flex-start;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n overflow-x: hidden;\n position: absolute;\n width: 90vw;\n color: var(--colour-text);\n}\n\n\n/* Footer */\n.footer {\n padding: 1vh 1vw;\n text-align: center;\n margin: 0;\n max-height: 5vh;\n overflow-y: auto;\n background-color: var(--colour-accent);\n position: absolute;\n bottom: 0;\n width: 98vw;\n}\n\n@media screen and (max-width: 400px) {\n .footer {\n max-height: 8vh;\n padding: 0 2vw;\n font-size: 10px; \n width: 96vw;\n max-width: 96vw;\n }\n .footer > h4 {\n font-size: 10px;\n }\n .footer > h5 {\n font-size: 9px;\n }\n}\n\n.footer > h4, h5 {\n padding: 0;\n margin: 0;\n}","\n/*\n#formFilters .container-input.filter.active_only {\n}\n*/\n\n\n#tableMain tbody > div {\n width: 113vh;\n}\n\n/*\n#tableMain tbody tr td table thead tr th.id_variation_type,\n#tableMain tbody tr td table tbody tr td.id_variation_type,\n#tableMain tbody tr td table thead tr th.id_variation, \n#tableMain tbody tr td table tbody tr td.id_variation {\n width: 47.5%;\n}\n*/\n#tableMain tbody tr td table thead tr th.button_shape, \n#tableMain tbody tr td table tbody tr td.button_shape,\n#tableMain tbody tr td table thead tr th.colour, \n#tableMain tbody tr td table tbody tr td.colour,\n#tableMain tbody tr td table thead tr th.button_icon, \n#tableMain tbody tr td table tbody tr td.button_icon {\n max-width: 12vh;\n max-width: 12vh;\n}\n\n/*\nselect.id_variation, select.id_variation_type {\n max-width: 40% !important;\n}\n*/\n\n@media screen and (max-width: 850px) {\n #formFilters input,\n #formFilters select {\n max-width: 12vh;\n min-width: 12vh;\n }\n}\n"],"names":[],"sourceRoot":""}

View File

@@ -1,38 +1,4 @@
.img-product {
max-width: 20vh;
max-height: 20vh;
border-radius: 3vh;
justify-self: left;
}
.img-thumbnail {
max-width: 10vh;
max-height: 10vh;
border-radius: 3vh;
justify-self: left;
}
.buttonAddToBasket {
background-color: var(--colour-page-background);
border-color: var(--colour-primary);
}
#buttonCheckout, .buttonBuyNow {
background-color: var(--colour-page-background);
/* color: var(--c_purple_dark); */
border-color: var(--colour-primary);
}
.button-increment, .button-decrement {
border: 2px solid darkgrey;
background-color: lightgray;
margin: 1vh 1vh;
width: 2.5vh;
height: 2.5vh;
border-radius: 1.25vh;
font-size: 2vh;
}
.container-input > input { .container-input > input {
padding: 0vh 1vh; padding: 0vh 1vh;
@@ -55,6 +21,59 @@
#pageBody {
/* height: 69vh !important; */
max-height: 79vh;
padding: 0 5vw;
margin: 0;
border: 0;
align-content: center;
justify-content: flex-start;
display: flex;
flex-direction: column;
align-items: flex-start;
overflow-y: auto;
overflow-x: hidden;
position: absolute;
width: 90vw;
color: var(--colour-text);
}
/* Footer */
.footer {
padding: 1vh 1vw;
text-align: center;
margin: 0;
max-height: 5vh;
overflow-y: auto;
background-color: var(--colour-accent);
position: absolute;
bottom: 0;
width: 98vw;
}
@media screen and (max-width: 400px) {
.footer {
max-height: 8vh;
padding: 0 2vw;
font-size: 10px;
width: 96vw;
max-width: 96vw;
}
.footer > h4 {
font-size: 10px;
}
.footer > h5 {
font-size: 9px;
}
}
.footer > h4, h5 {
padding: 0;
margin: 0;
}
#formFilters #search { #formFilters #search {
max-width: 20vh; max-width: 20vh;
min-width: 20vh; min-width: 20vh;

View File

@@ -1 +1 @@
{"version":3,"file":"css/dog_command_categories.bundle.css","mappings":";AACA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,+CAA+C;IAC/C,mCAAmC;AACvC;;AAEA;IACI,+CAA+C;IAC/C,iCAAiC;IACjC,mCAAmC;AACvC;;AAEA;IACI,0BAA0B;IAC1B,2BAA2B;IAC3B,eAAe;IACf,YAAY;IACZ,aAAa;IACb,qBAAqB;IACrB,cAAc;AAClB;;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;;;;ACpDf;IACI,eAAe;IACf,eAAe;AACnB;;AAEA;IACI,eAAe;AACnB;AACA;;IAEI,WAAW;AACf;AACA;IACI,sCAAsC;AAC1C;AACA;;;CAGC;AACD;;IAEI,eAAe;IACf,eAAe;AACnB;;AAEA;IACI;;QAEI,eAAe;QACf,eAAe;IACnB;IACA;;QAEI,cAAc;QACd,cAAc;IAClB;AACJ,C","sources":["webpack://app/./static/css/sections/dog.css","webpack://app/./static/css/pages/dog/command_categories.css"],"sourcesContent":["\n.img-product {\n max-width: 20vh;\n max-height: 20vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.img-thumbnail {\n max-width: 10vh;\n max-height: 10vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.buttonAddToBasket {\n background-color: var(--colour-page-background);\n border-color: var(--colour-primary);\n}\n\n#buttonCheckout, .buttonBuyNow {\n background-color: var(--colour-page-background);\n /* color: var(--c_purple_dark); */\n border-color: var(--colour-primary);\n}\n\n.button-increment, .button-decrement {\n border: 2px solid darkgrey;\n background-color: lightgray;\n margin: 1vh 1vh;\n width: 2.5vh;\n height: 2.5vh;\n border-radius: 1.25vh;\n font-size: 2vh;\n}\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n","\n#formFilters #search {\n max-width: 20vh;\n min-width: 20vh;\n}\n\n#tableMain tbody > div {\n max-width: 58vh;\n}\n#tableMain thead tr th,\n#tableMain tbody tr td {\n height: 3vh;\n}\n#tableMain tbody tr td.name .name {\n border: 1px solid var(--colour-accent);\n}\n/*\n#tableMain thead tr th.code,\n#tableMain tbody tr td.code,\n*/\n#tableMain thead tr th.name ,\n#tableMain tbody tr td.name {\n max-width: 50vh;\n min-width: 50vh;\n}\n\n@media screen and (max-width: 800px) {\n #tableMain thead tr th.name ,\n #tableMain tbody tr td.name {\n max-width: 63vw;\n min-width: 63vw;\n }\n #tableMain thead tr th.active ,\n #tableMain tbody tr td.active {\n max-width: 3vw;\n min-width: 3vw;\n }\n}"],"names":[],"sourceRoot":""} {"version":3,"file":"css/dog_command_categories.bundle.css","mappings":";;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;;;;AAIf;IACI,6BAA6B;IAC7B,gBAAgB;IAChB,cAAc;IACd,SAAS;IACT,SAAS;IACT,qBAAqB;IACrB,2BAA2B;IAC3B,aAAa;IACb,sBAAsB;IACtB,uBAAuB;IACvB,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;IAClB,WAAW;IACX,yBAAyB;AAC7B;;;AAGA,WAAW;AACX;IACI,gBAAgB;IAChB,kBAAkB;IAClB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,sCAAsC;IACtC,kBAAkB;IAClB,SAAS;IACT,WAAW;AACf;;AAEA;IACI;QACI,eAAe;QACf,cAAc;QACd,eAAe;QACf,WAAW;QACX,eAAe;IACnB;IACA;QACI,eAAe;IACnB;IACA;QACI,cAAc;IAClB;AACJ;;AAEA;IACI,UAAU;IACV,SAAS;AACb,C;;ACzEA;IACI,eAAe;IACf,eAAe;AACnB;;AAEA;IACI,eAAe;AACnB;AACA;;IAEI,WAAW;AACf;AACA;IACI,sCAAsC;AAC1C;AACA;;;CAGC;AACD;;IAEI,eAAe;IACf,eAAe;AACnB;;AAEA;IACI;;QAEI,eAAe;QACf,eAAe;IACnB;IACA;;QAEI,cAAc;QACd,cAAc;IAClB;AACJ,C","sources":["webpack://app/./static/css/sections/dog.css","webpack://app/./static/css/pages/dog/command_categories.css"],"sourcesContent":["\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n\n\n#pageBody {\n /* height: 69vh !important; */\n max-height: 79vh;\n padding: 0 5vw;\n margin: 0;\n border: 0;\n align-content: center;\n justify-content: flex-start;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n overflow-x: hidden;\n position: absolute;\n width: 90vw;\n color: var(--colour-text);\n}\n\n\n/* Footer */\n.footer {\n padding: 1vh 1vw;\n text-align: center;\n margin: 0;\n max-height: 5vh;\n overflow-y: auto;\n background-color: var(--colour-accent);\n position: absolute;\n bottom: 0;\n width: 98vw;\n}\n\n@media screen and (max-width: 400px) {\n .footer {\n max-height: 8vh;\n padding: 0 2vw;\n font-size: 10px; \n width: 96vw;\n max-width: 96vw;\n }\n .footer > h4 {\n font-size: 10px;\n }\n .footer > h5 {\n font-size: 9px;\n }\n}\n\n.footer > h4, h5 {\n padding: 0;\n margin: 0;\n}","\n#formFilters #search {\n max-width: 20vh;\n min-width: 20vh;\n}\n\n#tableMain tbody > div {\n max-width: 58vh;\n}\n#tableMain thead tr th,\n#tableMain tbody tr td {\n height: 3vh;\n}\n#tableMain tbody tr td.name .name {\n border: 1px solid var(--colour-accent);\n}\n/*\n#tableMain thead tr th.code,\n#tableMain tbody tr td.code,\n*/\n#tableMain thead tr th.name ,\n#tableMain tbody tr td.name {\n max-width: 50vh;\n min-width: 50vh;\n}\n\n@media screen and (max-width: 800px) {\n #tableMain thead tr th.name ,\n #tableMain tbody tr td.name {\n max-width: 63vw;\n min-width: 63vw;\n }\n #tableMain thead tr th.active ,\n #tableMain tbody tr td.active {\n max-width: 3vw;\n min-width: 3vw;\n }\n}"],"names":[],"sourceRoot":""}

View File

@@ -1,38 +1,4 @@
.img-product {
max-width: 20vh;
max-height: 20vh;
border-radius: 3vh;
justify-self: left;
}
.img-thumbnail {
max-width: 10vh;
max-height: 10vh;
border-radius: 3vh;
justify-self: left;
}
.buttonAddToBasket {
background-color: var(--colour-page-background);
border-color: var(--colour-primary);
}
#buttonCheckout, .buttonBuyNow {
background-color: var(--colour-page-background);
/* color: var(--c_purple_dark); */
border-color: var(--colour-primary);
}
.button-increment, .button-decrement {
border: 2px solid darkgrey;
background-color: lightgray;
margin: 1vh 1vh;
width: 2.5vh;
height: 2.5vh;
border-radius: 1.25vh;
font-size: 2vh;
}
.container-input > input { .container-input > input {
padding: 0vh 1vh; padding: 0vh 1vh;
@@ -55,6 +21,59 @@
#pageBody {
/* height: 69vh !important; */
max-height: 79vh;
padding: 0 5vw;
margin: 0;
border: 0;
align-content: center;
justify-content: flex-start;
display: flex;
flex-direction: column;
align-items: flex-start;
overflow-y: auto;
overflow-x: hidden;
position: absolute;
width: 90vw;
color: var(--colour-text);
}
/* Footer */
.footer {
padding: 1vh 1vw;
text-align: center;
margin: 0;
max-height: 5vh;
overflow-y: auto;
background-color: var(--colour-accent);
position: absolute;
bottom: 0;
width: 98vw;
}
@media screen and (max-width: 400px) {
.footer {
max-height: 8vh;
padding: 0 2vw;
font-size: 10px;
width: 96vw;
max-width: 96vw;
}
.footer > h4 {
font-size: 10px;
}
.footer > h5 {
font-size: 9px;
}
}
.footer > h4, h5 {
padding: 0;
margin: 0;
}
/* /*
#formFilters .container { #formFilters .container {
max-width: fit-content; max-width: fit-content;

View File

@@ -1 +1 @@
{"version":3,"file":"css/dog_commands.bundle.css","mappings":";AACA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,+CAA+C;IAC/C,mCAAmC;AACvC;;AAEA;IACI,+CAA+C;IAC/C,iCAAiC;IACjC,mCAAmC;AACvC;;AAEA;IACI,0BAA0B;IAC1B,2BAA2B;IAC3B,eAAe;IACf,YAAY;IACZ,aAAa;IACb,qBAAqB;IACrB,cAAc;AAClB;;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;;;;ACpDf;;;;CAIC;;AAED;IACI,WAAW;AACf;AACA;;IAEI,cAAc;IACd,cAAc;AAClB;;AAEA;;;;;;;;CAQC,C","sources":["webpack://app/./static/css/sections/dog.css","webpack://app/./static/css/pages/dog/commands.css"],"sourcesContent":["\n.img-product {\n max-width: 20vh;\n max-height: 20vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.img-thumbnail {\n max-width: 10vh;\n max-height: 10vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.buttonAddToBasket {\n background-color: var(--colour-page-background);\n border-color: var(--colour-primary);\n}\n\n#buttonCheckout, .buttonBuyNow {\n background-color: var(--colour-page-background);\n /* color: var(--c_purple_dark); */\n border-color: var(--colour-primary);\n}\n\n.button-increment, .button-decrement {\n border: 2px solid darkgrey;\n background-color: lightgray;\n margin: 1vh 1vh;\n width: 2.5vh;\n height: 2.5vh;\n border-radius: 1.25vh;\n font-size: 2vh;\n}\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n","\n/*\n#formFilters .container {\n max-width: fit-content;\n}\n*/\n\n#tableMain tbody > div {\n width: 99vh;\n}\n#tableMain thead tr th.can-have-button, \n#tableMain tbody tr td.can-have-button {\n max-width: 6vh;\n min-width: 6vh;\n}\n\n/*\n@media screen and (max-width: 600px) {\n #formFilters input,\n #formFilters select {\n width: 12vh;\n min-width: 12vh;\n }\n}\n*/"],"names":[],"sourceRoot":""} {"version":3,"file":"css/dog_commands.bundle.css","mappings":";;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;;;;AAIf;IACI,6BAA6B;IAC7B,gBAAgB;IAChB,cAAc;IACd,SAAS;IACT,SAAS;IACT,qBAAqB;IACrB,2BAA2B;IAC3B,aAAa;IACb,sBAAsB;IACtB,uBAAuB;IACvB,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;IAClB,WAAW;IACX,yBAAyB;AAC7B;;;AAGA,WAAW;AACX;IACI,gBAAgB;IAChB,kBAAkB;IAClB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,sCAAsC;IACtC,kBAAkB;IAClB,SAAS;IACT,WAAW;AACf;;AAEA;IACI;QACI,eAAe;QACf,cAAc;QACd,eAAe;QACf,WAAW;QACX,eAAe;IACnB;IACA;QACI,eAAe;IACnB;IACA;QACI,cAAc;IAClB;AACJ;;AAEA;IACI,UAAU;IACV,SAAS;AACb,C;;ACzEA;;;;CAIC;;AAED;IACI,WAAW;AACf;AACA;;IAEI,cAAc;IACd,cAAc;AAClB;;AAEA;;;;;;;;CAQC,C","sources":["webpack://app/./static/css/sections/dog.css","webpack://app/./static/css/pages/dog/commands.css"],"sourcesContent":["\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n\n\n#pageBody {\n /* height: 69vh !important; */\n max-height: 79vh;\n padding: 0 5vw;\n margin: 0;\n border: 0;\n align-content: center;\n justify-content: flex-start;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n overflow-x: hidden;\n position: absolute;\n width: 90vw;\n color: var(--colour-text);\n}\n\n\n/* Footer */\n.footer {\n padding: 1vh 1vw;\n text-align: center;\n margin: 0;\n max-height: 5vh;\n overflow-y: auto;\n background-color: var(--colour-accent);\n position: absolute;\n bottom: 0;\n width: 98vw;\n}\n\n@media screen and (max-width: 400px) {\n .footer {\n max-height: 8vh;\n padding: 0 2vw;\n font-size: 10px; \n width: 96vw;\n max-width: 96vw;\n }\n .footer > h4 {\n font-size: 10px;\n }\n .footer > h5 {\n font-size: 9px;\n }\n}\n\n.footer > h4, h5 {\n padding: 0;\n margin: 0;\n}","\n/*\n#formFilters .container {\n max-width: fit-content;\n}\n*/\n\n#tableMain tbody > div {\n width: 99vh;\n}\n#tableMain thead tr th.can-have-button, \n#tableMain tbody tr td.can-have-button {\n max-width: 6vh;\n min-width: 6vh;\n}\n\n/*\n@media screen and (max-width: 600px) {\n #formFilters input,\n #formFilters select {\n width: 12vh;\n min-width: 12vh;\n }\n}\n*/"],"names":[],"sourceRoot":""}

View File

@@ -1,38 +1,4 @@
.img-product {
max-width: 20vh;
max-height: 20vh;
border-radius: 3vh;
justify-self: left;
}
.img-thumbnail {
max-width: 10vh;
max-height: 10vh;
border-radius: 3vh;
justify-self: left;
}
.buttonAddToBasket {
background-color: var(--colour-page-background);
border-color: var(--colour-primary);
}
#buttonCheckout, .buttonBuyNow {
background-color: var(--colour-page-background);
/* color: var(--c_purple_dark); */
border-color: var(--colour-primary);
}
.button-increment, .button-decrement {
border: 2px solid darkgrey;
background-color: lightgray;
margin: 1vh 1vh;
width: 2.5vh;
height: 2.5vh;
border-radius: 1.25vh;
font-size: 2vh;
}
.container-input > input { .container-input > input {
padding: 0vh 1vh; padding: 0vh 1vh;
@@ -55,6 +21,59 @@
#pageBody {
/* height: 69vh !important; */
max-height: 79vh;
padding: 0 5vw;
margin: 0;
border: 0;
align-content: center;
justify-content: flex-start;
display: flex;
flex-direction: column;
align-items: flex-start;
overflow-y: auto;
overflow-x: hidden;
position: absolute;
width: 90vw;
color: var(--colour-text);
}
/* Footer */
.footer {
padding: 1vh 1vw;
text-align: center;
margin: 0;
max-height: 5vh;
overflow-y: auto;
background-color: var(--colour-accent);
position: absolute;
bottom: 0;
width: 98vw;
}
@media screen and (max-width: 400px) {
.footer {
max-height: 8vh;
padding: 0 2vw;
font-size: 10px;
width: 96vw;
max-width: 96vw;
}
.footer > h4 {
font-size: 10px;
}
.footer > h5 {
font-size: 9px;
}
}
.footer > h4, h5 {
padding: 0;
margin: 0;
}
/* /*
#formFilters .container-input.filter.active_only { #formFilters .container-input.filter.active_only {
} }

View File

@@ -1 +1 @@
{"version":3,"file":"css/dog_dog_command_links.bundle.css","mappings":";AACA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,+CAA+C;IAC/C,mCAAmC;AACvC;;AAEA;IACI,+CAA+C;IAC/C,iCAAiC;IACjC,mCAAmC;AACvC;;AAEA;IACI,0BAA0B;IAC1B,2BAA2B;IAC3B,eAAe;IACf,YAAY;IACZ,aAAa;IACb,qBAAqB;IACrB,cAAc;AAClB;;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;;;;ACpDf;;;CAGC;;;AAGD;IACI,YAAY;AAChB;AACA;IACI,eAAe;AACnB;;AAEA;;;;;;IAMI,uCAAuC;IACvC,oBAAoB;AACxB;;AAEA;;;;IAII,YAAY;AAChB;;AAEA;;;;CAIC;;AAED;IACI;;QAEI,eAAe;QACf,eAAe;IACnB;AACJ","sources":["webpack://app/./static/css/sections/dog.css","webpack://app/./static/css/pages/dog/dog_command_links.css"],"sourcesContent":["\n.img-product {\n max-width: 20vh;\n max-height: 20vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.img-thumbnail {\n max-width: 10vh;\n max-height: 10vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.buttonAddToBasket {\n background-color: var(--colour-page-background);\n border-color: var(--colour-primary);\n}\n\n#buttonCheckout, .buttonBuyNow {\n background-color: var(--colour-page-background);\n /* color: var(--c_purple_dark); */\n border-color: var(--colour-primary);\n}\n\n.button-increment, .button-decrement {\n border: 2px solid darkgrey;\n background-color: lightgray;\n margin: 1vh 1vh;\n width: 2.5vh;\n height: 2.5vh;\n border-radius: 1.25vh;\n font-size: 2vh;\n}\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n","\n/*\n#formFilters .container-input.filter.active_only {\n}\n*/\n\n\n#tableMain tbody > div {\n width: 113vh;\n}\n#tableMain {\n max-width: 90vw;\n}\n\ntd > input,\ntd > select,\ntd > textarea,\n.container-input > input,\n.container-input > select,\n.container-input > textarea {\n border: 2px solid var(--colour-primary);\n border-radius: 0.5vh;\n}\n\n#tableMain tbody tr td table thead tr th.id_variation_type,\n#tableMain tbody tr td table tbody tr td.id_variation_type,\n#tableMain tbody tr td table thead tr th.id_variation, \n#tableMain tbody tr td table tbody tr td.id_variation {\n width: 47.5%;\n}\n\n/*\nselect.id_variation, select.id_variation_type {\n max-width: 40% !important;\n}\n*/\n\n@media screen and (max-width: 850px) {\n #formFilters input,\n #formFilters select {\n max-width: 12vh;\n min-width: 12vh;\n }\n}\n"],"names":[],"sourceRoot":""} {"version":3,"file":"css/dog_dog_command_links.bundle.css","mappings":";;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;;;;AAIf;IACI,6BAA6B;IAC7B,gBAAgB;IAChB,cAAc;IACd,SAAS;IACT,SAAS;IACT,qBAAqB;IACrB,2BAA2B;IAC3B,aAAa;IACb,sBAAsB;IACtB,uBAAuB;IACvB,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;IAClB,WAAW;IACX,yBAAyB;AAC7B;;;AAGA,WAAW;AACX;IACI,gBAAgB;IAChB,kBAAkB;IAClB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,sCAAsC;IACtC,kBAAkB;IAClB,SAAS;IACT,WAAW;AACf;;AAEA;IACI;QACI,eAAe;QACf,cAAc;QACd,eAAe;QACf,WAAW;QACX,eAAe;IACnB;IACA;QACI,eAAe;IACnB;IACA;QACI,cAAc;IAClB;AACJ;;AAEA;IACI,UAAU;IACV,SAAS;AACb,C;;ACzEA;;;CAGC;;;AAGD;IACI,YAAY;AAChB;AACA;IACI,eAAe;AACnB;;AAEA;;;;;;IAMI,uCAAuC;IACvC,oBAAoB;AACxB;;AAEA;;;;IAII,YAAY;AAChB;;AAEA;;;;CAIC;;AAED;IACI;;QAEI,eAAe;QACf,eAAe;IACnB;AACJ","sources":["webpack://app/./static/css/sections/dog.css","webpack://app/./static/css/pages/dog/dog_command_links.css"],"sourcesContent":["\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n\n\n#pageBody {\n /* height: 69vh !important; */\n max-height: 79vh;\n padding: 0 5vw;\n margin: 0;\n border: 0;\n align-content: center;\n justify-content: flex-start;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n overflow-x: hidden;\n position: absolute;\n width: 90vw;\n color: var(--colour-text);\n}\n\n\n/* Footer */\n.footer {\n padding: 1vh 1vw;\n text-align: center;\n margin: 0;\n max-height: 5vh;\n overflow-y: auto;\n background-color: var(--colour-accent);\n position: absolute;\n bottom: 0;\n width: 98vw;\n}\n\n@media screen and (max-width: 400px) {\n .footer {\n max-height: 8vh;\n padding: 0 2vw;\n font-size: 10px; \n width: 96vw;\n max-width: 96vw;\n }\n .footer > h4 {\n font-size: 10px;\n }\n .footer > h5 {\n font-size: 9px;\n }\n}\n\n.footer > h4, h5 {\n padding: 0;\n margin: 0;\n}","\n/*\n#formFilters .container-input.filter.active_only {\n}\n*/\n\n\n#tableMain tbody > div {\n width: 113vh;\n}\n#tableMain {\n max-width: 90vw;\n}\n\ntd > input,\ntd > select,\ntd > textarea,\n.container-input > input,\n.container-input > select,\n.container-input > textarea {\n border: 2px solid var(--colour-primary);\n border-radius: 0.5vh;\n}\n\n#tableMain tbody tr td table thead tr th.id_variation_type,\n#tableMain tbody tr td table tbody tr td.id_variation_type,\n#tableMain tbody tr td table thead tr th.id_variation, \n#tableMain tbody tr td table tbody tr td.id_variation {\n width: 47.5%;\n}\n\n/*\nselect.id_variation, select.id_variation_type {\n max-width: 40% !important;\n}\n*/\n\n@media screen and (max-width: 850px) {\n #formFilters input,\n #formFilters select {\n max-width: 12vh;\n min-width: 12vh;\n }\n}\n"],"names":[],"sourceRoot":""}

View File

@@ -1,38 +1,4 @@
.img-product {
max-width: 20vh;
max-height: 20vh;
border-radius: 3vh;
justify-self: left;
}
.img-thumbnail {
max-width: 10vh;
max-height: 10vh;
border-radius: 3vh;
justify-self: left;
}
.buttonAddToBasket {
background-color: var(--colour-page-background);
border-color: var(--colour-primary);
}
#buttonCheckout, .buttonBuyNow {
background-color: var(--colour-page-background);
/* color: var(--c_purple_dark); */
border-color: var(--colour-primary);
}
.button-increment, .button-decrement {
border: 2px solid darkgrey;
background-color: lightgray;
margin: 1vh 1vh;
width: 2.5vh;
height: 2.5vh;
border-radius: 1.25vh;
font-size: 2vh;
}
.container-input > input { .container-input > input {
padding: 0vh 1vh; padding: 0vh 1vh;
@@ -55,5 +21,58 @@
#pageBody {
/* height: 69vh !important; */
max-height: 79vh;
padding: 0 5vw;
margin: 0;
border: 0;
align-content: center;
justify-content: flex-start;
display: flex;
flex-direction: column;
align-items: flex-start;
overflow-y: auto;
overflow-x: hidden;
position: absolute;
width: 90vw;
color: var(--colour-text);
}
/* Footer */
.footer {
padding: 1vh 1vw;
text-align: center;
margin: 0;
max-height: 5vh;
overflow-y: auto;
background-color: var(--colour-accent);
position: absolute;
bottom: 0;
width: 98vw;
}
@media screen and (max-width: 400px) {
.footer {
max-height: 8vh;
padding: 0 2vw;
font-size: 10px;
width: 96vw;
max-width: 96vw;
}
.footer > h4 {
font-size: 10px;
}
.footer > h5 {
font-size: 9px;
}
}
.footer > h4, h5 {
padding: 0;
margin: 0;
}
/*# sourceMappingURL=dog_dogs.bundle.css.map*/ /*# sourceMappingURL=dog_dogs.bundle.css.map*/

View File

@@ -1 +1 @@
{"version":3,"file":"css/dog_dogs.bundle.css","mappings":";AACA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,+CAA+C;IAC/C,mCAAmC;AACvC;;AAEA;IACI,+CAA+C;IAC/C,iCAAiC;IACjC,mCAAmC;AACvC;;AAEA;IACI,0BAA0B;IAC1B,2BAA2B;IAC3B,eAAe;IACf,YAAY;IACZ,aAAa;IACb,qBAAqB;IACrB,cAAc;AAClB;;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe","sources":["webpack://app/./static/css/sections/dog.css"],"sourcesContent":["\n.img-product {\n max-width: 20vh;\n max-height: 20vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.img-thumbnail {\n max-width: 10vh;\n max-height: 10vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.buttonAddToBasket {\n background-color: var(--colour-page-background);\n border-color: var(--colour-primary);\n}\n\n#buttonCheckout, .buttonBuyNow {\n background-color: var(--colour-page-background);\n /* color: var(--c_purple_dark); */\n border-color: var(--colour-primary);\n}\n\n.button-increment, .button-decrement {\n border: 2px solid darkgrey;\n background-color: lightgray;\n margin: 1vh 1vh;\n width: 2.5vh;\n height: 2.5vh;\n border-radius: 1.25vh;\n font-size: 2vh;\n}\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n"],"names":[],"sourceRoot":""} {"version":3,"file":"css/dog_dogs.bundle.css","mappings":";;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;;;;AAIf;IACI,6BAA6B;IAC7B,gBAAgB;IAChB,cAAc;IACd,SAAS;IACT,SAAS;IACT,qBAAqB;IACrB,2BAA2B;IAC3B,aAAa;IACb,sBAAsB;IACtB,uBAAuB;IACvB,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;IAClB,WAAW;IACX,yBAAyB;AAC7B;;;AAGA,WAAW;AACX;IACI,gBAAgB;IAChB,kBAAkB;IAClB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,sCAAsC;IACtC,kBAAkB;IAClB,SAAS;IACT,WAAW;AACf;;AAEA;IACI;QACI,eAAe;QACf,cAAc;QACd,eAAe;QACf,WAAW;QACX,eAAe;IACnB;IACA;QACI,eAAe;IACnB;IACA;QACI,cAAc;IAClB;AACJ;;AAEA;IACI,UAAU;IACV,SAAS;AACb,C","sources":["webpack://app/./static/css/sections/dog.css"],"sourcesContent":["\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n\n\n#pageBody {\n /* height: 69vh !important; */\n max-height: 79vh;\n padding: 0 5vw;\n margin: 0;\n border: 0;\n align-content: center;\n justify-content: flex-start;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n overflow-x: hidden;\n position: absolute;\n width: 90vw;\n color: var(--colour-text);\n}\n\n\n/* Footer */\n.footer {\n padding: 1vh 1vw;\n text-align: center;\n margin: 0;\n max-height: 5vh;\n overflow-y: auto;\n background-color: var(--colour-accent);\n position: absolute;\n bottom: 0;\n width: 98vw;\n}\n\n@media screen and (max-width: 400px) {\n .footer {\n max-height: 8vh;\n padding: 0 2vw;\n font-size: 10px; \n width: 96vw;\n max-width: 96vw;\n }\n .footer > h4 {\n font-size: 10px;\n }\n .footer > h5 {\n font-size: 9px;\n }\n}\n\n.footer > h4, h5 {\n padding: 0;\n margin: 0;\n}"],"names":[],"sourceRoot":""}

View File

@@ -1,38 +1,4 @@
.img-product {
max-width: 20vh;
max-height: 20vh;
border-radius: 3vh;
justify-self: left;
}
.img-thumbnail {
max-width: 10vh;
max-height: 10vh;
border-radius: 3vh;
justify-self: left;
}
.buttonAddToBasket {
background-color: var(--colour-page-background);
border-color: var(--colour-primary);
}
#buttonCheckout, .buttonBuyNow {
background-color: var(--colour-page-background);
/* color: var(--c_purple_dark); */
border-color: var(--colour-primary);
}
.button-increment, .button-decrement {
border: 2px solid darkgrey;
background-color: lightgray;
margin: 1vh 1vh;
width: 2.5vh;
height: 2.5vh;
border-radius: 1.25vh;
font-size: 2vh;
}
.container-input > input { .container-input > input {
padding: 0vh 1vh; padding: 0vh 1vh;
@@ -54,6 +20,59 @@
/* Main Table */ /* Main Table */
#pageBody {
/* height: 69vh !important; */
max-height: 79vh;
padding: 0 5vw;
margin: 0;
border: 0;
align-content: center;
justify-content: flex-start;
display: flex;
flex-direction: column;
align-items: flex-start;
overflow-y: auto;
overflow-x: hidden;
position: absolute;
width: 90vw;
color: var(--colour-text);
}
/* Footer */
.footer {
padding: 1vh 1vw;
text-align: center;
margin: 0;
max-height: 5vh;
overflow-y: auto;
background-color: var(--colour-accent);
position: absolute;
bottom: 0;
width: 98vw;
}
@media screen and (max-width: 400px) {
.footer {
max-height: 8vh;
padding: 0 2vw;
font-size: 10px;
width: 96vw;
max-width: 96vw;
}
.footer > h4 {
font-size: 10px;
}
.footer > h5 {
font-size: 9px;
}
}
.footer > h4, h5 {
padding: 0;
margin: 0;
}
#pageBody .column .row { #pageBody .column .row {
margin-top: 0.5vh; margin-top: 0.5vh;
} }

View File

@@ -1 +1 @@
{"version":3,"file":"css/dog_home.bundle.css","mappings":";AACA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,+CAA+C;IAC/C,mCAAmC;AACvC;;AAEA;IACI,+CAA+C;IAC/C,iCAAiC;IACjC,mCAAmC;AACvC;;AAEA;IACI,0BAA0B;IAC1B,2BAA2B;IAC3B,eAAe;IACf,YAAY;IACZ,aAAa;IACb,qBAAqB;IACrB,cAAc;AAClB;;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;;;ACrDf;IACI,iBAAiB;AACrB;AACA;IACI,iBAAiB;IACjB,kBAAkB;AACtB,C","sources":["webpack://app/./static/css/sections/dog.css","webpack://app/./static/css/pages/dog/home.css"],"sourcesContent":["\n.img-product {\n max-width: 20vh;\n max-height: 20vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.img-thumbnail {\n max-width: 10vh;\n max-height: 10vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.buttonAddToBasket {\n background-color: var(--colour-page-background);\n border-color: var(--colour-primary);\n}\n\n#buttonCheckout, .buttonBuyNow {\n background-color: var(--colour-page-background);\n /* color: var(--c_purple_dark); */\n border-color: var(--colour-primary);\n}\n\n.button-increment, .button-decrement {\n border: 2px solid darkgrey;\n background-color: lightgray;\n margin: 1vh 1vh;\n width: 2.5vh;\n height: 2.5vh;\n border-radius: 1.25vh;\n font-size: 2vh;\n}\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n","#pageBody .column .row {\n margin-top: 0.5vh;\n}\n#pageBody .column .row .button {\n margin-left: auto;\n margin-right: auto;\n}"],"names":[],"sourceRoot":""} {"version":3,"file":"css/dog_home.bundle.css","mappings":";;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;;;;AAIf;IACI,6BAA6B;IAC7B,gBAAgB;IAChB,cAAc;IACd,SAAS;IACT,SAAS;IACT,qBAAqB;IACrB,2BAA2B;IAC3B,aAAa;IACb,sBAAsB;IACtB,uBAAuB;IACvB,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;IAClB,WAAW;IACX,yBAAyB;AAC7B;;;AAGA,WAAW;AACX;IACI,gBAAgB;IAChB,kBAAkB;IAClB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,sCAAsC;IACtC,kBAAkB;IAClB,SAAS;IACT,WAAW;AACf;;AAEA;IACI;QACI,eAAe;QACf,cAAc;QACd,eAAe;QACf,WAAW;QACX,eAAe;IACnB;IACA;QACI,eAAe;IACnB;IACA;QACI,cAAc;IAClB;AACJ;;AAEA;IACI,UAAU;IACV,SAAS;AACb,C;AC1EA;IACI,iBAAiB;AACrB;AACA;IACI,iBAAiB;IACjB,kBAAkB;AACtB,C","sources":["webpack://app/./static/css/sections/dog.css","webpack://app/./static/css/pages/dog/home.css"],"sourcesContent":["\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n\n\n#pageBody {\n /* height: 69vh !important; */\n max-height: 79vh;\n padding: 0 5vw;\n margin: 0;\n border: 0;\n align-content: center;\n justify-content: flex-start;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n overflow-x: hidden;\n position: absolute;\n width: 90vw;\n color: var(--colour-text);\n}\n\n\n/* Footer */\n.footer {\n padding: 1vh 1vw;\n text-align: center;\n margin: 0;\n max-height: 5vh;\n overflow-y: auto;\n background-color: var(--colour-accent);\n position: absolute;\n bottom: 0;\n width: 98vw;\n}\n\n@media screen and (max-width: 400px) {\n .footer {\n max-height: 8vh;\n padding: 0 2vw;\n font-size: 10px; \n width: 96vw;\n max-width: 96vw;\n }\n .footer > h4 {\n font-size: 10px;\n }\n .footer > h5 {\n font-size: 9px;\n }\n}\n\n.footer > h4, h5 {\n padding: 0;\n margin: 0;\n}","#pageBody .column .row {\n margin-top: 0.5vh;\n}\n#pageBody .column .row .button {\n margin-left: auto;\n margin-right: auto;\n}"],"names":[],"sourceRoot":""}

View File

@@ -1,38 +1,4 @@
.img-product {
max-width: 20vh;
max-height: 20vh;
border-radius: 3vh;
justify-self: left;
}
.img-thumbnail {
max-width: 10vh;
max-height: 10vh;
border-radius: 3vh;
justify-self: left;
}
.buttonAddToBasket {
background-color: var(--colour-page-background);
border-color: var(--colour-primary);
}
#buttonCheckout, .buttonBuyNow {
background-color: var(--colour-page-background);
/* color: var(--c_purple_dark); */
border-color: var(--colour-primary);
}
.button-increment, .button-decrement {
border: 2px solid darkgrey;
background-color: lightgray;
margin: 1vh 1vh;
width: 2.5vh;
height: 2.5vh;
border-radius: 1.25vh;
font-size: 2vh;
}
.container-input > input { .container-input > input {
padding: 0vh 1vh; padding: 0vh 1vh;
@@ -55,6 +21,59 @@
#pageBody {
/* height: 69vh !important; */
max-height: 79vh;
padding: 0 5vw;
margin: 0;
border: 0;
align-content: center;
justify-content: flex-start;
display: flex;
flex-direction: column;
align-items: flex-start;
overflow-y: auto;
overflow-x: hidden;
position: absolute;
width: 90vw;
color: var(--colour-text);
}
/* Footer */
.footer {
padding: 1vh 1vw;
text-align: center;
margin: 0;
max-height: 5vh;
overflow-y: auto;
background-color: var(--colour-accent);
position: absolute;
bottom: 0;
width: 98vw;
}
@media screen and (max-width: 400px) {
.footer {
max-height: 8vh;
padding: 0 2vw;
font-size: 10px;
width: 96vw;
max-width: 96vw;
}
.footer > h4 {
font-size: 10px;
}
.footer > h5 {
font-size: 9px;
}
}
.footer > h4, h5 {
padding: 0;
margin: 0;
}
#tableMain tbody > div { #tableMain tbody > div {
width: 49vh; width: 49vh;

View File

@@ -1 +1 @@
{"version":3,"file":"css/dog_locations.bundle.css","mappings":";AACA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;AACtB;;AAEA;IACI,+CAA+C;IAC/C,mCAAmC;AACvC;;AAEA;IACI,+CAA+C;IAC/C,iCAAiC;IACjC,mCAAmC;AACvC;;AAEA;IACI,0BAA0B;IAC1B,2BAA2B;IAC3B,eAAe;IACf,YAAY;IACZ,aAAa;IACb,qBAAqB;IACrB,cAAc;AAClB;;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;;;;;ACnDf;IACI,WAAW;AACf","sources":["webpack://app/./static/css/sections/dog.css","webpack://app/./static/css/pages/dog/locations.css"],"sourcesContent":["\n.img-product {\n max-width: 20vh;\n max-height: 20vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.img-thumbnail {\n max-width: 10vh;\n max-height: 10vh;\n border-radius: 3vh;\n justify-self: left;\n}\n\n.buttonAddToBasket {\n background-color: var(--colour-page-background);\n border-color: var(--colour-primary);\n}\n\n#buttonCheckout, .buttonBuyNow {\n background-color: var(--colour-page-background);\n /* color: var(--c_purple_dark); */\n border-color: var(--colour-primary);\n}\n\n.button-increment, .button-decrement {\n border: 2px solid darkgrey;\n background-color: lightgray;\n margin: 1vh 1vh;\n width: 2.5vh;\n height: 2.5vh;\n border-radius: 1.25vh;\n font-size: 2vh;\n}\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n","\n\n#tableMain tbody > div {\n width: 49vh;\n}\n"],"names":[],"sourceRoot":""} {"version":3,"file":"css/dog_locations.bundle.css","mappings":";;AAEA;IACI,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;AAClB;;AAEA;IACI,eAAe;AACnB;;;;AAIA,iBAAiB;AACjB;IACI,sBAAsB;AAC1B;;AAEA,eAAe;;;;AAIf;IACI,6BAA6B;IAC7B,gBAAgB;IAChB,cAAc;IACd,SAAS;IACT,SAAS;IACT,qBAAqB;IACrB,2BAA2B;IAC3B,aAAa;IACb,sBAAsB;IACtB,uBAAuB;IACvB,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;IAClB,WAAW;IACX,yBAAyB;AAC7B;;;AAGA,WAAW;AACX;IACI,gBAAgB;IAChB,kBAAkB;IAClB,SAAS;IACT,eAAe;IACf,gBAAgB;IAChB,sCAAsC;IACtC,kBAAkB;IAClB,SAAS;IACT,WAAW;AACf;;AAEA;IACI;QACI,eAAe;QACf,cAAc;QACd,eAAe;QACf,WAAW;QACX,eAAe;IACnB;IACA;QACI,eAAe;IACnB;IACA;QACI,cAAc;IAClB;AACJ;;AAEA;IACI,UAAU;IACV,SAAS;AACb,C;;;ACxEA;IACI,WAAW;AACf","sources":["webpack://app/./static/css/sections/dog.css","webpack://app/./static/css/pages/dog/locations.css"],"sourcesContent":["\n\n.container-input > input {\n padding: 0vh 1vh;\n border-radius: 0.5vh;\n max-width: 7vh;\n}\n\n#basket {\n max-width: 100%;\n}\n\n\n\n/* Right column */\n.rightcolumn {\n min-width: fit-content;\n}\n\n/* Main Table */\n\n\n\n#pageBody {\n /* height: 69vh !important; */\n max-height: 79vh;\n padding: 0 5vw;\n margin: 0;\n border: 0;\n align-content: center;\n justify-content: flex-start;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n overflow-x: hidden;\n position: absolute;\n width: 90vw;\n color: var(--colour-text);\n}\n\n\n/* Footer */\n.footer {\n padding: 1vh 1vw;\n text-align: center;\n margin: 0;\n max-height: 5vh;\n overflow-y: auto;\n background-color: var(--colour-accent);\n position: absolute;\n bottom: 0;\n width: 98vw;\n}\n\n@media screen and (max-width: 400px) {\n .footer {\n max-height: 8vh;\n padding: 0 2vw;\n font-size: 10px; \n width: 96vw;\n max-width: 96vw;\n }\n .footer > h4 {\n font-size: 10px;\n }\n .footer > h5 {\n font-size: 9px;\n }\n}\n\n.footer > h4, h5 {\n padding: 0;\n margin: 0;\n}","\n\n#tableMain tbody > div {\n width: 49vh;\n}\n"],"names":[],"sourceRoot":""}

View File

@@ -59,8 +59,9 @@ script, link {
display: none !important; display: none !important;
} }
/*
#pageBody { #pageBody {
/* height: 69vh !important; */ / * height: 69vh !important; * /
max-height: 79vh; max-height: 79vh;
padding: 0 5vw; padding: 0 5vw;
margin: 0; margin: 0;
@@ -76,6 +77,7 @@ script, link {
width: 90vw; width: 90vw;
color: var(--colour-text); color: var(--colour-text);
} }
*/
.page-body > * { .page-body > * {
display: flex; display: flex;
@@ -117,7 +119,7 @@ img.header-logo {
background-color: var(--colour-text-background); background-color: var(--colour-text-background);
padding: 1vh 2.5vw; padding: 1vh 2.5vw;
margin: 1vh; margin: 1vh;
display: flex !important; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -210,6 +212,8 @@ img.header-logo {
ul { ul {
max-width: 90%; max-width: 90%;
padding: 5px 0 10px 0; padding: 5px 0 10px 0;
width: fit-content;
margin: auto;
} }
li { li {
text-align: left; text-align: left;
@@ -521,45 +525,6 @@ table div {
align-content: center; align-content: center;
} }
/*
header {
background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
/ * position: fixed;
top: 0; * /
width: 100%;
z-index: 1000;
}
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 0;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
color: var(--primary);
}
.nav-links {
display: flex;
gap: 2rem;
}
.nav-links a {
text-decoration: none;
color: var(--text);
font-weight: 500;
align-content: center;
}
.nav-links a.button {
color: white;
}
*/
/* Navigation */ /* Navigation */
.topnav { .topnav {
@@ -717,40 +682,7 @@ form.filter button.save, form.filter button.button-cancel {
font-size: 16px; font-size: 16px;
} }
} }
/* In sections */
/* Footer */
.footer {
padding: 1vh 1vw;
text-align: center;
margin: 0;
max-height: 5vh;
overflow-y: auto;
background-color: var(--colour-accent);
position: absolute;
bottom: 0;
width: 98vw;
}
@media screen and (max-width: 400px) {
.footer {
max-height: 8vh;
padding: 0 2vw;
font-size: 10px;
width: 96vw;
max-width: 96vw;
}
.footer > h4 {
font-size: 10px;
}
.footer > h5 {
font-size: 9px;
}
}
.footer > h4, h5 {
padding: 0;
margin: 0;
}
#formFilters { #formFilters {
padding: 0.5vh 1vw; padding: 0.5vh 1vw;
@@ -834,7 +766,7 @@ table.table-main tbody tr td.notes {
table.table-main tbody tr td:has(.dirty) { table.table-main tbody tr td:has(.dirty) {
background-color: var(--colour-primary); background-color: var(--colour-primary);
} }
table.table-main tbody tr td:has(.dirty) table { table.table-main tbody tr td:has(.dirty) table tr:not(:has(.dirty)) {
background-color: var(--colour-text-background); background-color: var(--colour-text-background);
} }
table.table-main tbody tr:not(:last-of-type) td { table.table-main tbody tr:not(:last-of-type) td {

File diff suppressed because one or more lines are too long

View File

@@ -1,153 +1,17 @@
/******/ (() => { // webpackBootstrap /******/ (() => { // webpackBootstrap
/******/ "use strict"; /******/ "use strict";
/******/ var __webpack_modules__ = ({ // This entry needs to be wrapped in an IIFE because it needs to be isolated against other entry modules.
(() => {
/***/ 561:
/***/ (() => {
// extracted by mini-css-extract-plugin // extracted by mini-css-extract-plugin
})();
/***/ }), // This entry needs to be wrapped in an IIFE because it needs to be isolated against other entry modules.
(() => {
/***/ 711:
/***/ (() => {
// extracted by mini-css-extract-plugin // extracted by mini-css-extract-plugin
})();
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = __webpack_modules__;
/******/
/************************************************************************/
/******/ /* webpack/runtime/chunk loaded */
/******/ (() => {
/******/ var deferred = [];
/******/ __webpack_require__.O = (result, chunkIds, fn, priority) => {
/******/ if(chunkIds) {
/******/ priority = priority || 0;
/******/ for(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];
/******/ deferred[i] = [chunkIds, fn, priority];
/******/ return;
/******/ }
/******/ var notFulfilled = Infinity;
/******/ for (var i = 0; i < deferred.length; i++) {
/******/ var [chunkIds, fn, priority] = deferred[i];
/******/ var fulfilled = true;
/******/ for (var j = 0; j < chunkIds.length; j++) {
/******/ if ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) {
/******/ chunkIds.splice(j--, 1);
/******/ } else {
/******/ fulfilled = false;
/******/ if(priority < notFulfilled) notFulfilled = priority;
/******/ }
/******/ }
/******/ if(fulfilled) {
/******/ deferred.splice(i--, 1)
/******/ var r = fn();
/******/ if (r !== undefined) result = r;
/******/ }
/******/ }
/******/ return result;
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/jsonp chunk loading */
/******/ (() => {
/******/ // no baseURI
/******/
/******/ // object to store loaded and loading chunks
/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
/******/ var installedChunks = {
/******/ 780: 0,
/******/ 466: 0
/******/ };
/******/
/******/ // no chunk on demand loading
/******/
/******/ // no prefetching
/******/
/******/ // no preloaded
/******/
/******/ // no HMR
/******/
/******/ // no HMR manifest
/******/
/******/ __webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);
/******/
/******/ // install a JSONP callback for chunk loading
/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
/******/ var [chunkIds, moreModules, runtime] = data;
/******/ // add "moreModules" to the modules object,
/******/ // then flag all "chunkIds" as loaded and fire callback
/******/ var moduleId, chunkId, i = 0;
/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
/******/ for(moduleId in moreModules) {
/******/ if(__webpack_require__.o(moreModules, moduleId)) {
/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
/******/ }
/******/ }
/******/ if(runtime) var result = runtime(__webpack_require__);
/******/ }
/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
/******/ for(;i < chunkIds.length; i++) {
/******/ chunkId = chunkIds[i];
/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
/******/ installedChunks[chunkId][0]();
/******/ }
/******/ installedChunks[chunkId] = 0;
/******/ }
/******/ return __webpack_require__.O(result);
/******/ }
/******/
/******/ var chunkLoadingGlobal = self["webpackChunkapp"] = self["webpackChunkapp"] || [];
/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
/******/ })();
/******/
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module depends on other loaded chunks and execution need to be delayed
/******/ __webpack_require__.O(undefined, [466], () => (__webpack_require__(711)))
/******/ var __webpack_exports__ = __webpack_require__.O(undefined, [466], () => (__webpack_require__(561)))
/******/ __webpack_exports__ = __webpack_require__.O(__webpack_exports__);
/******/
/******/ })() /******/ })()
; ;
//# sourceMappingURL=core_admin_home.bundle.js.map //# sourceMappingURL=core_admin_home.bundle.js.map

File diff suppressed because one or more lines are too long

17
static/dist/js/core_contact.bundle.js vendored Normal file
View File

@@ -0,0 +1,17 @@
/******/ (() => { // webpackBootstrap
/******/ "use strict";
// This entry needs to be wrapped in an IIFE because it needs to be isolated against other entry modules.
(() => {
// extracted by mini-css-extract-plugin
})();
// This entry needs to be wrapped in an IIFE because it needs to be isolated against other entry modules.
(() => {
// extracted by mini-css-extract-plugin
})();
/******/ })()
;
//# sourceMappingURL=core_contact.bundle.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"js/core_contact.bundle.js","mappings":";;;;AAAA;;;;;;ACAA","sources":["webpack://app/./static/css/sections/core.css?6d04","webpack://app/./static/css/pages/core/contact.css?164a"],"sourcesContent":["// extracted by mini-css-extract-plugin\nexport {};","// extracted by mini-css-extract-plugin\nexport {};"],"names":[],"sourceRoot":""}

View File

@@ -1,153 +1,17 @@
/******/ (() => { // webpackBootstrap /******/ (() => { // webpackBootstrap
/******/ "use strict"; /******/ "use strict";
/******/ var __webpack_modules__ = ({ // This entry needs to be wrapped in an IIFE because it needs to be isolated against other entry modules.
(() => {
/***/ 805:
/***/ (() => {
// extracted by mini-css-extract-plugin // extracted by mini-css-extract-plugin
})();
/***/ }), // This entry needs to be wrapped in an IIFE because it needs to be isolated against other entry modules.
(() => {
/***/ 711:
/***/ (() => {
// extracted by mini-css-extract-plugin // extracted by mini-css-extract-plugin
})();
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = __webpack_modules__;
/******/
/************************************************************************/
/******/ /* webpack/runtime/chunk loaded */
/******/ (() => {
/******/ var deferred = [];
/******/ __webpack_require__.O = (result, chunkIds, fn, priority) => {
/******/ if(chunkIds) {
/******/ priority = priority || 0;
/******/ for(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];
/******/ deferred[i] = [chunkIds, fn, priority];
/******/ return;
/******/ }
/******/ var notFulfilled = Infinity;
/******/ for (var i = 0; i < deferred.length; i++) {
/******/ var [chunkIds, fn, priority] = deferred[i];
/******/ var fulfilled = true;
/******/ for (var j = 0; j < chunkIds.length; j++) {
/******/ if ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) {
/******/ chunkIds.splice(j--, 1);
/******/ } else {
/******/ fulfilled = false;
/******/ if(priority < notFulfilled) notFulfilled = priority;
/******/ }
/******/ }
/******/ if(fulfilled) {
/******/ deferred.splice(i--, 1)
/******/ var r = fn();
/******/ if (r !== undefined) result = r;
/******/ }
/******/ }
/******/ return result;
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/jsonp chunk loading */
/******/ (() => {
/******/ // no baseURI
/******/
/******/ // object to store loaded and loading chunks
/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
/******/ var installedChunks = {
/******/ 664: 0,
/******/ 466: 0
/******/ };
/******/
/******/ // no chunk on demand loading
/******/
/******/ // no prefetching
/******/
/******/ // no preloaded
/******/
/******/ // no HMR
/******/
/******/ // no HMR manifest
/******/
/******/ __webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);
/******/
/******/ // install a JSONP callback for chunk loading
/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
/******/ var [chunkIds, moreModules, runtime] = data;
/******/ // add "moreModules" to the modules object,
/******/ // then flag all "chunkIds" as loaded and fire callback
/******/ var moduleId, chunkId, i = 0;
/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
/******/ for(moduleId in moreModules) {
/******/ if(__webpack_require__.o(moreModules, moduleId)) {
/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
/******/ }
/******/ }
/******/ if(runtime) var result = runtime(__webpack_require__);
/******/ }
/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
/******/ for(;i < chunkIds.length; i++) {
/******/ chunkId = chunkIds[i];
/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
/******/ installedChunks[chunkId][0]();
/******/ }
/******/ installedChunks[chunkId] = 0;
/******/ }
/******/ return __webpack_require__.O(result);
/******/ }
/******/
/******/ var chunkLoadingGlobal = self["webpackChunkapp"] = self["webpackChunkapp"] || [];
/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
/******/ })();
/******/
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module depends on other loaded chunks and execution need to be delayed
/******/ __webpack_require__.O(undefined, [466], () => (__webpack_require__(711)))
/******/ var __webpack_exports__ = __webpack_require__.O(undefined, [466], () => (__webpack_require__(805)))
/******/ __webpack_exports__ = __webpack_require__.O(__webpack_exports__);
/******/
/******/ })() /******/ })()
; ;
//# sourceMappingURL=core_home.bundle.js.map //# sourceMappingURL=core_home.bundle.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -61,6 +61,7 @@ export default class BasePage {
}); });
this.hookupButtonsNavHome(); this.hookupButtonsNavHome();
this.hookupButtonsNavContact();
// this.hookupButtonsNavAdminHome(); // this.hookupButtonsNavAdminHome();
this.hookupButtonsNavUserAccount(); this.hookupButtonsNavUserAccount();
this.hookupButtonsNavUserLogout(); this.hookupButtonsNavUserLogout();
@@ -94,6 +95,9 @@ export default class BasePage {
this.router.navigateToHash(hashPageNav); this.router.navigateToHash(hashPageNav);
}); });
} }
hookupButtonsNavContact() {
this.hookupButtonsNav('.' + flagNavContact, hashPageContact);
}
/* /*
hookupButtonsNavAdminHome() { hookupButtonsNavAdminHome() {
this.hookupButtonsNav('.' + flagNavAdminHome, hashPageAdminHome); this.hookupButtonsNav('.' + flagNavAdminHome, hashPageAdminHome);

View File

@@ -0,0 +1,16 @@
// internal
import BasePage from "../base.js";
// vendor
import { Altcha } from "../../vendor/altcha.js";
export default class PageContactSuccess extends BasePage {
static hash = hashPageContactSuccess;
constructor(router) {
super(router);
}
initialize() {
this.sharedInitialize();
}
}

View File

@@ -0,0 +1,23 @@
// internal
import BasePage from "../base.js";
// vendor
import { Altcha } from "../../vendor/altcha.js";
export default class PageContact extends BasePage {
static hash = hashPageContact;
constructor(router) {
super(router);
}
initialize() {
this.sharedInitialize();
this.hookupButtonSubmitFormContactUs();
}
hookupButtonSubmitFormContactUs() {
const button = document.querySelector('form input[type="submit"]');
button.classList.add(flagButton);
button.classList.add(flagButtonPrimary);
}
}

View File

@@ -2,6 +2,8 @@
// Pages // Pages
// Core // Core
import PageHome from './pages/core/home.js'; import PageHome from './pages/core/home.js';
import PageContact from './pages/core/contact.js';
import PageContactSuccess from './pages/core/contact-success.js';
// Dog // Dog
import PageDogHome from './pages/dog/home.js'; import PageDogHome from './pages/dog/home.js';
import PageDogCommandCategories from './pages/dog/command_categories.js'; import PageDogCommandCategories from './pages/dog/command_categories.js';
@@ -35,6 +37,8 @@ export default class Router {
this.pages = {}; this.pages = {};
// Core // Core
this.pages[hashPageHome] = { name: 'PageHome', module: PageHome }; this.pages[hashPageHome] = { name: 'PageHome', module: PageHome };
this.pages[hashPageContact] = { name: 'PageContact', module: PageContact };
this.pages[hashPageContactSuccess] = { name: 'PageContactSuccess', module: PageContactSuccess };
// Dog // Dog
this.pages[hashPageDogHome] = { name: 'PageDogHome', module: PageDogHome }; this.pages[hashPageDogHome] = { name: 'PageDogHome', module: PageDogHome };
this.pages[hashPageDogCommandCategories] = { name: 'PageDogCommands', module: PageDogCommandCategories }; this.pages[hashPageDogCommandCategories] = { name: 'PageDogCommands', module: PageDogCommandCategories };
@@ -59,6 +63,8 @@ export default class Router {
this.routes = {}; this.routes = {};
// Core // Core
this.routes[hashPageHome] = (isPopState = false) => this.navigateToHash(hashPageHome, isPopState); this.routes[hashPageHome] = (isPopState = false) => this.navigateToHash(hashPageHome, isPopState);
this.routes[hashPageContact] = (isPopState = false) => this.navigateToHash(hashPageContact, isPopState);
this.routes[hashPageContactSuccess] = (isPopState = false) => this.navigateToHash(hashPageContactSuccess, isPopState);
// Dog // Dog
this.routes[hashPageDogHome] = (isPopState = false) => this.navigateToHash(hashPageDogHome, isPopState); this.routes[hashPageDogHome] = (isPopState = false) => this.navigateToHash(hashPageDogHome, isPopState);
this.routes[hashPageDogCommandCategories] = (isPopState = false) => this.navigateToHash(hashPageDogCommandCategories, isPopState); this.routes[hashPageDogCommandCategories] = (isPopState = false) => this.navigateToHash(hashPageDogCommandCategories, isPopState);

23
static/js/test.js Normal file
View File

@@ -0,0 +1,23 @@
document.querySelectorAll('#_r_j_ ul li.bg-card').forEach((li) => {
let ratingElement = li.querySelector('section.grid.gap-x-2.items-center.grid-cols-[60px_1fr].sm:flex.grid-rows-[15px_1fr_1fr].sm:grid-rows-1 span.[&>a]:font-semibold.font-semibold.flex.bg-secondary-soft.text-secondary-altFg.rounded-xl.max-w-fit-content.min-w-14.justify-center.p-2.shrink.text-lg.row-start-2.row-span-2');
let rating = ratingElement.innerText;
let nameElement = li.querySelector('section.grid.gap-x-2.items-center.grid-cols-[60px_1fr].sm:flex.grid-rows-[15px_1fr_1fr].sm:grid-rows-1 h3.text-text-neutral-primary.text-base.font-bold.row-span-2.row-start-2.col-start-2');
let name = nameElement.innerText
let postedOnElement = li.querySelector('section.grid.gap-x-2.items-center.grid-cols-[60px_1fr].sm:flex.grid-rows-[15px_1fr_1fr].sm:grid-rows-1 p.[&>a]:font-semibold.font-normal.text-neutral-strong.text-xxs.ml-auto.shrink-0.row-start-1.col-start-2');
let postedOn = contentElement.innerText;
let contentElement = li.querySelector('');
console.log("\nReview");
console.log(`Rating: ${rating}`);
console.log(`Rating: ${rating}`);
console.log(`Rating: ${rating}`);
console.log(`Rating: ${rating}`);
console.log(`Rating: ${rating}`);
console.log(`Rating: ${rating}`);
});
/*
html body.flex.h-full.flex-col.bg-main.text-main-fg.antialiased.__variable_605d37.__variable_6549f3.__className_6549f3 main.flex.min-h-screen.flex-col.items-center.justify-between div.flex.size-full.min-h-screen.flex-col.items-center.justify-between.bg-neutral-0 div.fixed.inset-0.flex.z-20.overflow-hidden dialog.fixed.left-0.top-0.z-50.m-0.size-full.max-h-none.max-w-none.bg-main.p-0.backdrop:bg-[#000]/50.backdrop:backdrop-blur-sm.md:bg-transparent.md:px-10.md:py-5 div#_r_j_.max-w-full.max-h-full.self-center.mx-auto.z-40.flex.size-full.flex-col.md:rounded-lg.md:bg-main.md:shadow-xl div.flex.flex-1.overflow-hidden div.flex-1.overflow-y-auto div.flex.flex-1.flex-col.items-center.gap-4.rounded-b-lg.bg-[#F4F3F0].px-4.py-6 ul.grid.w-full.grid-cols-1.gap-4 li.bg-card.rounded-2xl.flex.flex-col.p-4.gap-3.border.border-neutral-200 section.grid.gap-x-2.items-center.grid-cols-[60px_1fr].sm:flex.grid-rows-[15px_1fr_1fr].sm:grid-rows-1 p.[&>a]:font-semibold.font-normal.text-neutral-strong.text-xxs.ml-auto.shrink-0.row-start-1.col-start-2
*/

View File

@@ -4,17 +4,17 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8"/> <meta charset="utf-8"/>
<title>{{ model.title }} - DOG</title> <title>{{ model.title }} - DOG</title>
<meta name="description" content="Professional dog training management software for UK trainers. Manage clients, track training sessions, monitor progress, and engage dog owners with our comprehensive SaaS platform. Starting from £15/month." /> <meta name="description" content="Explore our wide range of software engineering services. We specialize in various tech stacks including MySQL, Python, Microsoft SQL Server, C#, Firebase, Node.js, Java, HTML5, React, CSS3, Flask, JavaScript, MVC, and REST." />
<meta name="keywords" content="fetch metrics, fetchmetrics, dog training software, dog trainer management, pet training app, canine training system, dog training business software, professional dog training, UK dog trainers, training session management, dog training records, client management for dog trainers, dog training progress tracking, pet training business tools, dog training scheduling, canine behavior tracking, dog trainer CRM, training appointment booking, dog training client portal, canine training documentation, dog obedience training, puppy training programs, behavioral modification, training milestones, dog training certificates, trainer scheduling, client communication, training homework assignments, progress reports, dog training analytics, British dog training, dog training software UK, professional dog training tools" /> <meta name="keywords" content="software engineering, software development, software design, software testing, software maintenance, software support, software consultancy, software training, software documentation, software project management, software quality assurance, software process improvement, software configuration management, software requirements engineering, software architecture, software design patterns, software design principles, software testing principles, software testing techniques, software testing tools, software testing automation, software testing manual, software testing exploratory, software testing regression, software testing performance, software testing security, software testing usability, software testing accessibility, software testing compatibility, software testing reliability, software testing maintainability, software testing portability, software testing scalability, software testing test-driven development, software testing behaviour-driven development, software testing acceptance test-driven development, software testing continuous integration, software testing continuous deployment, software testing continuous delivery, software testing continuous monitoring, software testing continuous feedback, software testing continuous improvement, software testing agile, software testing scrum, software testing kanban, software testing lean, software testing waterfall, software testing v-model, software testing spiral, software testing incremental, software testing iterative, software testing adaptive, software testing predictive, software testing hybrid, software testing manual, software testing automated, software testing exploratory, software testing regression, software testing performance, software testing security, software testing usability, software testing accessibility, software testing compatibility, software testing reliability, software testing maintainability, software testing portability, software testing scalability, software testing test-driven development, software testing behaviour-driven development, software testing acceptance test-driven development, software testing continuous integration, software testing continuous deployment, software testing continuous delivery, software testing continuous monitoring, software testing continuous feedback, software testing continuous improvement, software testing agile, software testing scrum, software testing kanban, software testing lean, software testing waterfall, software testing v-model, software testing spiral, software testing incremental, software testing iterative, software testing adaptive, software testing predictive, software testing hybrid, software testing manual, software testing automated, software testing exploratory, software testing regression, software testing performance, software testing security, software testing usability, software testing accessibility, software testing compatibility, software testing reliability, software testing maintainability, software testing portability, software testing scalability, software testing test-driven development, software testing behaviour-driven development, software testing acceptance test-driven development, software testing continuous integration, software testing continuous deployment, software testing continuous delivery, software testing continuous monitoring, software testing continuous feedback, software testing continuous improvement, software testing agile, software testing, MySQL, Python, Microsoft SQL Server, MS SQL Server, C#, Firebase, Node.js, Java, HTML5, React, CSS3, Flask, JavaScript, MVC, REST" />
<link rel="canonical" href="{{ model.get_url_host() }}" /> <link rel="canonical" href="{{ model.get_url_host() }}" />
<script type="application/ld+json"> <script type="application/ld+json">
{ {
"@context": "https://schema.org", "@context": "https://schema.org",
"@type": "ProfessionalService", "@type": "ProfessionalService",
"name": "Dog Training", "name": "{{ model.NAME_COMPANY_SHORT }}",
"url": "{{ model.get_url_host() }}", "url": "{{ model.get_url_host() }}",
"logo": "{{ model.get_url_host() }}{{ url_for('static', filename='images/Wisp_LQ.webp') }}", "logo": "{{ model.get_url_host() }}{{ url_for('static', filename='images/Logo.png') }}",
"description": "Fetch Metrics - Professional dog training management software for UK trainers. Manage clients, track training sessions, monitor progress, and engage dog owners with our comprehensive SaaS platform. Starting from £15/month.", "description": "Explore our wide range of software engineering services. We specialize in various tech stacks including MySQL, Python, Microsoft SQL Server, C#, Firebase, Node.js, Java, HTML5, React, CSS3, Flask, JavaScript, MVC, and REST.",
"address": { "address": {
"@type": "PostalAddress", "@type": "PostalAddress",
"streetAddress": "53 Alfred Green Close", "streetAddress": "53 Alfred Green Close",
@@ -29,15 +29,141 @@
"longitude": "1.16" "longitude": "1.16"
}, },
"openingHours": "Mo,Tu,We,Th,Fr 09:00-17:00", "openingHours": "Mo,Tu,We,Th,Fr 09:00-17:00",
"priceRange": "$", "priceRange": "$$",
} }
</script> </script>
<meta name="yandex-verification" content="e8c84f13a578a656" /> <!-- fetch-metrics.co.uk --> <meta name="yandex-verification" content="4693a824cfda082a" />
<meta name="yandex-verification" content="054b13bc60fb1625" /> <!-- fetch-metrics.com -->
<meta name="yandex-verification" content="f3c1a9bc28976419" /> <!-- fetchmetrics.co.uk -->
<meta id="{{ model.ID_CSRF_TOKEN }}" name="{{ model.FLAG_CSRF_TOKEN }}" content="{{ csrf_token() }}" /> <meta id="{{ model.ID_CSRF_TOKEN }}" name="{{ model.FLAG_CSRF_TOKEN }}" content="{{ csrf_token() }}" />
<script> <script>
{#
var attrIdAccessLevel = "{{ model.ATTR_ID_ACCESS_LEVEL }}";
var attrIdCurrency = "{{ model.ATTR_ID_CURRENCY }}";
var attrIdAddress = "{{ model.ATTR_ID_ADDRESS }}";
var attrIdPlant = "{{ model.ATTR_ID_PLANT }}";
var attrIdRegion = "{{ model.ATTR_ID_REGION }}";
var attrIdStorageLocation = "{{ model.ATTR_ID_STORAGE_LOCATION }}";
var attrTextCollapsed = "{{ model.ATTR_TEXT_COLLAPSED }}";
var attrTextExpanded = "{{ model.ATTR_TEXT_EXPANDED }}";
var attrValueCurrent = "{{ model.ATTR_VALUE_CURRENT }}";
var attrValuePrevious = "{{ model.ATTR_VALUE_PREVIOUS }}";
var attrValueNew = "{{ model.ATTR_VALUE_NEW }}";
var environment = {
"name": "{{ model.app.app_config.FLASK_ENV }}",
"is_production": "{{ model.app.app_config.is_production }}",
"is_development": "{{ model.app.app_config.is_development }}",
};
var flagAccessLevel = "{{ model.FLAG_ACCESS_LEVEL }}";
var flagAccessLevelRequired = "{{ model.FLAG_ACCESS_LEVEL_REQUIRED }}";
var flagActive = "{{ model.FLAG_ACTIVE }}";
var flagAdd = "{{ model.FLAG_ADD }}";
var flagAddress = "{{ model.FLAG_ADDRESS }}";
var flagAddressLine1 = "{{ model.FLAG_ADDRESS_LINE_1 }}";
var flagAddressLine2 = "{{ model.FLAG_ADDRESS_LINE_2 }}";
var flagButton = "{{ model.FLAG_BUTTON }}";
var flagButtonPrimary = "{{ model.FLAG_BUTTON_PRIMARY }}";
var flagCallback = "{{ model.FLAG_CALLBACK }}";
var flagCancel = "{{ model.FLAG_CANCEL }}";
var flagCard = "{{ model.FLAG_CARD }}";
var flagCity = "{{ model.FLAG_CITY }}";
var flagCloseTemporaryElement = "{{ model.FLAG_CLOSE_TEMPORARY_ELEMENT }}";
var flagCode = "{{ model.FLAG_CODE }}";
var flagCollapsed = "{{ model.FLAG_COLLAPSED }}";
var flagCollapsible = "{{ model.FLAG_COLLAPSIBLE }}";
var flagColumn = "{{ model.FLAG_COLUMN }}";
var flagComment = "{{ model.FLAG_COMMENT }}";
// var flagContactUs = "{{ model.FLAG_CONTACT_US }}";
var flagContainer = "{{ model.FLAG_CONTAINER }}";
var flagContainerCheckbox = "{{ model.FLAG_CONTAINER_CHECKBOX }}";
var flagContainerInput = "{{ model.FLAG_CONTAINER_INPUT }}";
var flagCounty = "{{ model.FLAG_COUNTY }}";
var flagCsrfToken = "{{ model.FLAG_CSRF_TOKEN }}";
var flagCurrency = "{{ model.FLAG_CURRENCY }}";
var flagDelete = "{{ model.FLAG_DELETE }}";
var flagDescription = "{{ model.FLAG_DESCRIPTION }}";
var flagDetail = "{{ model.FLAG_DETAIL }}";
var flagDialog = "{{ model.FLAG_DIALOG }}";
var flagDirty = "{{ model.FLAG_DIRTY }}";
var flagDisplayOrder = "{{ model.FLAG_DISPLAY_ORDER }}";
var flagDragging = "dragging";
var flagDragOver = "drag-over";
var flagEdit = "{{ model.FLAG_EDIT }}";
var flagEmail = "{{ model.FLAG_EMAIL }}";
var flagError = "{{ model.FLAG_ERROR }}";
var flagExpanded = "{{ model.FLAG_EXPANDED }}";
var flagFailure = "{{ model.FLAG_FAILURE }}";
var flagFax = "{{ model.FLAG_FAX }}";
var flagFilter = "{{ model.FLAG_FILTER }}";
var flagForm = "{{ model.FLAG_FORM }}";
var flagFormFilters = "{{ model.FLAG_FORM_FILTERS }}";
var flagImageLogo = "{{ model.FLAG_IMAGE_LOGO }}";
var flagInitialised = "{{ model.FLAG_INITIALISED }}";
// var flagItems = "{{ model.FLAG_ITEMS }}";
// var flagKeyPrimary = "{{ model.FLAG_KEY_PRIMARY }}";
var flagLeftHandStub = "{{ model.FLAG_LEFT_HAND_STUB }}";
var flagLogo = "{{ model.FLAG_LOGO }}";
var flagMessage = "{{ model.FLAG_MESSAGE }}";
var flagModal = "{{ model.FLAG_MODAL }}";
var flagMove = "move";
var flagName = "{{ model.FLAG_NAME }}";
var flagNameAttrOptionText = "{{ model.FLAG_NAME_ATTR_OPTION_TEXT}}";
var flagNameAttrOptionValue = "{{ model.FLAG_NAME_ATTR_OPTION_VALUE }}";
var flagNamePlural = "{{ model.FLAG_NAME_PLURAL }}";
var flagNavAdminHome = "{{ model.FLAG_NAV_ADMIN_HOME }}";
var flagNavContact = "{{ model.FLAG_NAV_CONTACT }}";
var flagNavHome = "{{ model.FLAG_NAV_HOME }}";
var flagNavServices = "{{ model.FLAG_NAV_SERVICES }}";
var flagNavUserAccount = "{{ model.FLAG_NAV_USER_ACCOUNT }}";
var flagNavUserAdmin = "{{ model.FLAG_NAV_USER_ADMIN }}";
var flagNavUserLogin = "{{ model.FLAG_NAV_USER_LOGIN }}";
var flagNavUserLogout = "{{ model.FLAG_NAV_USER_LOGOUT }}";
var flagOverlay = "{{ model.FLAG_OVERLAY }}";
var flagOverlayClose = "{{ model.FLAG_OVERLAY_CLOSE }}";
var flagPageBody = "{{ model.FLAG_PAGE_BODY }}";
var flagPhoneNumber = "{{ model.FLAG_PHONE_NUMBER }}";
var flagPostcode = "{{ model.FLAG_POSTCODE }}";
var flagCaptcha = "{{ model.FLAG_CAPTCHA }}";
var flagRightHandSide = "{{ model.FLAG_RIGHT_HAND_SIDE }}";
var flagRow = "{{ model.FLAG_ROW }}";
var flagRowNew = "{{ model.FLAG_ROW_NEW }}";
var flagRows = "{{ model.FLAG_ROWS }}";
var flagSave = "{{ model.FLAG_SAVE }}";
var flagScrollable = "{{ model.FLAG_SCROLLABLE }}";
var flagSlider = "{{ model.FLAG_SLIDER }}";
var flagStatus = "{{ model.FLAG_STATUS }}";
var flagSubmit = "{{ model.FLAG_SUBMIT }}";
var flagSubmitted = "{{ model.FLAG_SUBMITTED }}";
var flagSuccess = "{{ model.FLAG_SUCCESS }}";
var flagTemporaryElement = "{{ model.FLAG_TEMPORARY_ELEMENT }}";
var flagUser = "{{ model.FLAG_USER }}";
var flagWebsite = "{{ model.FLAG_WEBSITE }}";
var hashGetALTCHAChallenge = "{{ model.HASH_ALTCHA_CREATE_CHALLENGE }}";
var hashPageAccessibilityReport = "{{ model.HASH_PAGE_ACCESSIBILITY_REPORT }}";
var hashPageAccessibilityStatement = "{{ model.HASH_PAGE_ACCESSIBILITY_STATEMENT }}";
var hashPageContact = "{{ model.HASH_PAGE_CONTACT }}";
var hashPageContactSuccess = "{{ model.HASH_PAGE_CONTACT_SUCCESS }}";
var hashPageDataRetentionSchedule = "{{ model.HASH_PAGE_DATA_RETENTION_SCHEDULE }}";
var hashPageErrorNoPermission = "{{ model.HASH_PAGE_ERROR_NO_PERMISSION }}";
var hashPageHome = "{{ model.HASH_PAGE_HOME }}";
var hashPageLicense = "{{ model.HASH_PAGE_LICENSE }}";
var hashPagePrivacyPolicy = "{{ model.HASH_PAGE_PRIVACY_POLICY }}";
var idButtonApplyFilters = "#{{ model.ID_BUTTON_APPLY_FILTERS }}";
var idButtonHamburger = "#{{ model.ID_BUTTON_HAMBURGER }}";
var idCSRFToken = "#{{ model.ID_CSRF_TOKEN }}";
var idFormFilters = "#{{ model.ID_FORM_FILTERS }}";
var idLabelError = "#{{ model.ID_LABEL_ERROR }}";
var idOverlayConfirm = "#{{ model.ID_OVERLAY_CONFIRM }}";
var idOverlayError = "#{{ model.ID_OVERLAY_ERROR }}";
var idOverlayHamburger = "#{{ model.ID_OVERLAY_HAMBURGER }}";
var idPageBody = "#{{ model.ID_PAGE_BODY }}";
var idTableMain = "#{{ model.ID_TABLE_MAIN }}";
var idTextareaConfirm = "#{{ model.ID_TEXTAREA_CONFIRM }}";
var isUserLoggedIn = "{{ model.output_bool(model.IS_USER_LOGGED_IN) }}";
var _pathHost = "{{ model.get_url_host() }}";
var _rowBlank = null;
var titlePageCurrent = "{{ model.title }}";
var _verbose = ("{{ model.app.app_config.DEBUG }}" == "True");
#}
var attrIdAssessment = "{{ model.ATTR_ID_ASSESSMENT }}"; var attrIdAssessment = "{{ model.ATTR_ID_ASSESSMENT }}";
var attrIdAssessmentCommandModalityLink = "{{ model.ATTR_ID_ASSESSMENT_COMMAND_MODALITY_LINK }}"; var attrIdAssessmentCommandModalityLink = "{{ model.ATTR_ID_ASSESSMENT_COMMAND_MODALITY_LINK }}";
var attrIdAssessmentResponse = "{{ model.ATTR_ID_ASSESSMENT_RESPONSE }}"; var attrIdAssessmentResponse = "{{ model.ATTR_ID_ASSESSMENT_RESPONSE }}";
@@ -265,73 +391,70 @@
{% block page_head %}{% endblock %} {% block page_head %}{% endblock %}
</head> </head>
<body data-page="{{ model.hash_page_current }}"> <body data-page="{{ model.hash_page_current }}">
<!-- Header -- > <!-- Header -->
<header> <header>
<div class="container"> <div class="container">
<nav class="navbar"> <nav class="navbar">
<div class="{{ model.FLAG_LOGO }}" href="{{ model.HASH_PAGE_HOME }}">{{ model.NAME_COMPANY }}</div> <div class="{{ model.FLAG_LOGO }}" href="{{ model.HASH_PAGE_HOME }}">{{ model.NAME_COMPANY_SHORT }}</div>
<div class="nav-links"> <div class="nav-links">
{% block page_nav_links %}{% endblock %} {% block page_nav_links %}{% endblock %}
</div> </div>
</nav> </nav>
</div> </div>
</header> </header>
-->
<div class="topnav">
<div class="{{ model.FLAG_CONTAINER }} header-logo"> <!-- style="width: 18vw; min-width: 18vw; max-width: 20vw;" -->
<img class="header-logo" src="{{ url_for('static', filename='images/Wisp_LQ.webp') }}" alt="Fetch Metrics logo" aria-label="Fetch Metrics logo" tabindex="0">
</div>
<div class="{{ model.FLAG_CONTAINER }} company-name"> <!-- style="width: 75vw; min-width: 65vw; max-width: 80vw;" -->
<h1 class="company-name">{{ model.NAME_COMPANY_SHORT }} - {{ model.title }}</h1>
</div>
{#
<div class="{{ model.FLAG_CONTAINER }}"> <!-- style="width: 7vw; min-width: 7vw; max-width: 15vw; justify-content: flex-end; " padding-left: 25%; -->
<button id="{{ model.ID_BUTTON_HAMBURGER }}" class="{{ model.FLAG_BUTTON }} {{ model.FLAG_BUTTON_PRIMARY }}" tabindex="1" alt="Hamburger menu button" aria-label="Hamburger menu button"></button>
</div>
#}
</div>
<!-- Hamburger navigation menu -->
{% include 'components/common/buttons/_icon_hamburger.html' %}
<div id="{{ model.ID_OVERLAY_HAMBURGER }}" class="{{ model.FLAG_OVERLAY}} {{ model.FLAG_HAMBURGER }} {{ model.FLAG_IS_COLLAPSED }}">
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<a class="{{ model.FLAG_NAV_HOME }}">Home</a>
</div>
{% if True or model.user.can_admin_dog %}
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<a class="{{ model.FLAG_NAV_DOG_HOME }}">Dog Home</a>
</div>
{% endif %}
{% if model.user.get_is_logged_in() %}
{#
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<a class="{{ model.FLAG_NAV_USER_ACCOUNT }}">Account</a>
</div>
#}
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<a class="{{ model.FLAG_NAV_USER_LOGOUT }}">Logout</a>
</div>
{% else %}
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<a class="{{ model.FLAG_NAV_USER_LOGIN }}">Login</a>
</div>
{% endif %}
</div>
<!-- Body --> <!-- Body -->
<div id="{{ model.ID_PAGE_BODY }}"> <div id="{{ model.ID_PAGE_BODY }}">
{% block page_body %}{% endblock %} {% block page_body %}{% endblock %}
</div> </div>
<!-- Footer --> <!-- Footer -->
<div class="footer"> <footer class="footer">
<h4>Copyright &copy; {{ model.NAME_COMPANY }}. <a href="{{ url_for('routes_legal.license') }}" alt="License" aria-label="License">All rights reserved.</a></h4> <div class="{{ model.FLAG_CONTAINER }}">
<h5>Company number 13587499</h5> <div class="footer-content">
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}"> <div class="footer-section">
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}"><p><a href="{{ url_for('routes_legal.accessibility_statement') }}" alt="Accessibility statement" aria-label="Accessibility statement">Accessibility statement</a></p></div> <h3>{{ model.NAME_COMPANY }}</h3>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}"><p><a href="{{ url_for('routes_legal.privacy_policy') }}" alt="Privacy notice" aria-label="Privacy notice">Privacy notice</a></p></div> <p>Company Number: {{ model.COMPANY_NUMBER }}</p>
<p>Registered in England and Wales</p>
<p>Registered Office: {{ model.COMPANY_ADDRESS_SHORT }}</p>
</div>
<div class="footer-section">
<h3>Legal</h3>
<ul>
<li><a href="{{ model.HASH_PAGE_PRIVACY_POLICY }}">Privacy Policy</a></li>
<li><a href="{{ model.HASH_PAGE_ACCESSIBILITY_STATEMENT }}">Accessibility Statement</a></li>
</ul>
</div>
<div class="footer-section">
<h3>Contact</h3>
<ul>
<li><a href="mailto:{{ model.get_mail_contact_public() }}">Email: {{ model.get_mail_contact_public() }}</a></li>
<li><a href="{{ model.URL_DISCORD }}">Discord: {{ model.USERNAME_DISCORD }}</a></li>
<!-- <li><a href="{{ model.URL_FACEBOOK }}">Facebook: {{ model.USERNAME_FACEBOOK }}</a></li> -->
<li><a href="{{ model.URL_GITHUB }}">GitHub: {{ model.USERNAME_GITHUB }}</a></li>
<li><a href="{{ model.URL_INSTAGRAM }}">Instagram: {{ model.USERNAME_INSTAGRAM }}</a></li>
</ul>
</div>
<div class="footer-section">
<h3 style="color: #1f2937;">Contact</h3>
<ul>
<!-- <li>Phone</li> -->
<!-- <li><a href="{{ model.URL_LINKEDIN }}">LinkedIn: {{ model.USERNAME_LINKEDIN }}</a></li> -->
<li><a href="{{ model.URL_REDDIT }}">Reddit: {{ model.USERNAME_REDDIT }}</a></li>
<li><a href="{{ model.URL_TIKTOK }}">TikTok: {{ model.USERNAME_TIKTOK }}</a></li>
<li><a href="{{ model.URL_TWITTER }}">Twitter: {{ model.USERNAME_TWITTER }}</a></li>
</ul>
</div>
</div>
<div class="footer-bottom">
<p>&copy; {{ current_year }} {{ model.NAME_COMPANY }}. <a href="{{ model.HASH_PAGE_LICENSE }}" alt="License" aria-label="License">All rights reserved.</a></p>
</div>
</div> </div>
</div> </footer>
<script src="{{ url_for('static', filename='dist/js/main.bundle.js') }}"></script> <script src="{{ url_for('static', filename='dist/js/main.bundle.js') }}"></script>
</body> </body>

View File

@@ -0,0 +1,341 @@
<!DOCTYPE html>
<html lang="en-GB">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8"/>
<title>{{ model.title }} - DOG</title>
<meta name="description" content="Professional dog training management software for UK trainers. Manage clients, track training sessions, monitor progress, and engage dog owners with our comprehensive SaaS platform. Starting from £15/month." />
<meta name="keywords" content="fetch metrics, fetchmetrics, dog training software, dog trainer management, pet training app, canine training system, dog training business software, professional dog training, UK dog trainers, training session management, dog training records, client management for dog trainers, dog training progress tracking, pet training business tools, dog training scheduling, canine behavior tracking, dog trainer CRM, training appointment booking, dog training client portal, canine training documentation, dog obedience training, puppy training programs, behavioral modification, training milestones, dog training certificates, trainer scheduling, client communication, training homework assignments, progress reports, dog training analytics, British dog training, dog training software UK, professional dog training tools" />
<link rel="canonical" href="{{ model.get_url_host() }}" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "ProfessionalService",
"name": "Dog Training",
"url": "{{ model.get_url_host() }}",
"logo": "{{ model.get_url_host() }}{{ url_for('static', filename='images/Wisp_LQ.webp') }}",
"description": "Fetch Metrics - Professional dog training management software for UK trainers. Manage clients, track training sessions, monitor progress, and engage dog owners with our comprehensive SaaS platform. Starting from £15/month.",
"address": {
"@type": "PostalAddress",
"streetAddress": "53 Alfred Green Close",
"addressLocality": "Rugby",
"addressRegion": "Warwickshire",
"postalCode": "CV22 6DN",
"addressCountry": "United Kingdom"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": "52.22",
"longitude": "1.16"
},
"openingHours": "Mo,Tu,We,Th,Fr 09:00-17:00",
"priceRange": "$",
}
</script>
<meta name="yandex-verification" content="e8c84f13a578a656" /> <!-- fetch-metrics.co.uk -->
<meta name="yandex-verification" content="054b13bc60fb1625" /> <!-- fetch-metrics.com -->
<meta name="yandex-verification" content="f3c1a9bc28976419" /> <!-- fetchmetrics.co.uk -->
<meta id="{{ model.ID_CSRF_TOKEN }}" name="{{ model.FLAG_CSRF_TOKEN }}" content="{{ csrf_token() }}" />
<script>
var attrIdAssessment = "{{ model.ATTR_ID_ASSESSMENT }}";
var attrIdAssessmentCommandModalityLink = "{{ model.ATTR_ID_ASSESSMENT_COMMAND_MODALITY_LINK }}";
var attrIdAssessmentResponse = "{{ model.ATTR_ID_ASSESSMENT_RESPONSE }}";
var attrIdAccessLevel = "{{ model.ATTR_ID_ACCESS_LEVEL }}";
var attrIdBribe = "{{ model.ATTR_ID_BRIBE }}";
var attrIdButtonColour = "{{ model.ATTR_ID_BUTTON_COLOUR }}";
var attrIdButtonIcon = "{{ model.ATTR_ID_BUTTON_ICON }}";
var attrIdButtonShape = "{{ model.ATTR_ID_BUTTON_SHAPE }}";
var attrIdColour = "{{ model.ATTR_ID_COLOUR }}";
var attrIdCommand = "{{ model.ATTR_ID_COMMAND }}";
var attrIdCommandButtonLink = "{{ model.ATTR_ID_COMMAND_BUTTON_LINK }}";
var attrIdCommandCategory = "{{ model.ATTR_ID_COMMAND_CATEGORY }}";
var attrIdCommandModality = "{{ model.ATTR_ID_COMMAND_MODALITY }}";
var attrIdCurrency = "{{ model.ATTR_ID_CURRENCY }}";
var attrIdDistraction = "{{ model.ATTR_ID_DISTRACTION }}";
var attrIdDistractionIntensityLevel = "{{ model.ATTR_ID_DISTRACTION_INTENSITY_LEVEL }}";
var attrIdDistractionType = "{{ model.ATTR_ID_DISTRACTION_TYPE }}";
var attrIdDog = "{{ model.ATTR_ID_DOG }}";
var attrIdDogCommandLink = "{{ model.ATTR_ID_DOG_COMMAND_LINK }}";
var attrIdLightingLevel = "{{ model.ATTR_ID_LIGHTING_LEVEL }}";
var attrIdLocation = "{{ model.ATTR_ID_LOCATION }}";
var attrIdWeather = "{{ model.ATTR_ID_WEATHER }}";
var attrTextCollapsed = "{{ model.ATTR_TEXT_COLLAPSED }}";
var attrTextExpanded = "{{ model.ATTR_TEXT_EXPANDED }}";
var attrValueCurrent = "{{ model.ATTR_VALUE_CURRENT }}";
var attrValuePrevious = "{{ model.ATTR_VALUE_PREVIOUS }}";
var attrValueNew = "{{ model.ATTR_VALUE_NEW }}";
var colourAccent = "{{ model.COLOUR_ACCENT }}";
var colourError = "{{ model.COLOUR_ERROR }}";
var colourPageBackground = "{{ model.COLOUR_PAGE_BACKGROUND }}";
var colourPageBackground1 = "{{ model.COLOUR_PAGE_BACKGROUND_1 }}";
var colourPageBackground2 = "{{ model.COLOUR_PAGE_BACKGROUND_2 }}";
var colourPrimary = "{{ model.COLOUR_PRIMARY }}";
var colourSecondary = "{{ model.COLOUR_SECONDARY }}";
var colourText = "{{ model.COLOUR_TEXT }}";
var colourTextBackground = "{{ model.COLOUR_TEXT_BACKGROUND }}";
var colourTextLinkUnvisited = "{{ model.COLOUR_TEXT_LINK_UNVISITED }}";
var colourTextLinkVisited = "{{ model.COLOUR_TEXT_LINK_VISITED }}";
var environment = {
"name": "{{ model.app.app_config.FLASK_ENV }}",
"is_production": "{{ model.app.app_config.is_production | lower }}",
"is_development": "{{ model.app.app_config.is_development | lower }}",
};
var flagAccessLevel = "{{ model.FLAG_ACCESS_LEVEL }}";
var flagAccessLevelRequired = "{{ model.FLAG_ACCESS_LEVEL_REQUIRED }}";
var flagActive = "{{ model.FLAG_ACTIVE }}";
var flagActiveOnly = "{{ model.FLAG_ACTIVE_ONLY }}";
var flagAdd = "{{ model.FLAG_ADD }}";
var flagAddress = "{{ model.FLAG_ADDRESS }}";
var flagAddressLine1 = "{{ model.FLAG_ADDRESS_LINE_1 }}";
var flagAddressLine2 = "{{ model.FLAG_ADDRESS_LINE_2 }}";
var flagAssessment = "{{ model.FLAG_ASSESSMENT }}";
var flagAssessmentCommandModalityLink = "{{ model.FLAG_ASSESSMENT_COMMAND_MODALITY_LINK }}";
var flagAssessmentResponse = "{{ model.FLAG_ASSESSMENT_RESPONSE }}";
var flagBribe = "{{ model.FLAG_BRIBE }}";
var flagButton = "{{ model.FLAG_BUTTON }}";
var flagButtonIcon = "{{ model.FLAG_BUTTON_ICON }}";
var flagButtonShape = "{{ model.FLAG_BUTTON_SHAPE }}";
var flagButtonPrimary = "{{ model.FLAG_BUTTON_PRIMARY }}";
var flagCallback = "{{ model.FLAG_CALLBACK }}";
var flagCancel = "{{ model.FLAG_CANCEL }}";
var flagCaptcha = "{{ model.FLAG_CAPTCHA }}";
var flagCard = "{{ model.FLAG_CARD }}";
var flagCheckbox = "{{ model.FLAG_CHECKBOX }}";
var flagCity = "{{ model.FLAG_CITY }}";
var flagCloseTemporaryElement = "{{ model.FLAG_CLOSE_TEMPORARY_ELEMENT }}";
var flagCode = "{{ model.FLAG_CODE }}";
var flagCollapsible = "{{ model.FLAG_COLLAPSIBLE }}";
var flagColour = "{{ model.FLAG_COLOUR }}";
var flagColumn = "{{ model.FLAG_COLUMN }}";
var flagCommand = "{{ model.FLAG_COMMAND }}";
var flagCommandButtonLink = "{{ model.FLAG_COMMAND_BUTTON_LINK }}";
var flagCommandCategory = "{{ model.FLAG_COMMAND_CATEGORY }}";
var flagComment = "{{ model.FLAG_COMMENT }}";
var flagContainer = "{{ model.FLAG_CONTAINER }}";
var flagContainerInput = "{{ model.FLAG_CONTAINER_INPUT }}";
var flagCounty = "{{ model.FLAG_COUNTY }}";
var flagCsrfToken = "{{ model.FLAG_CSRF_TOKEN }}";
var flagCurrency = "{{ model.FLAG_CURRENCY }}";
var flagDdlPreview = "{{ model.FLAG_DDL_PREVIEW }}";
var flagDelete = "{{ model.FLAG_DELETE }}";
var flagDescription = "{{ model.FLAG_DESCRIPTION }}";
var flagDetail = "{{ model.FLAG_DETAIL }}";
var flagDialog = "{{ model.FLAG_DIALOG }}";
var flagDirty = "{{ model.FLAG_DIRTY }}";
var flagDisplayOrder = "{{ model.FLAG_DISPLAY_ORDER }}";
var flagDistraction = "{{ model.FLAG_DISTRACTION }}";
var flagDistractionIntensityLevel = "{{ model.FLAG_DISTRACTION_INTENSITY_LEVEL }}";
var flagDistractionType = "{{ model.FLAG_DISTRACTION_TYPE }}";
var flagDog = "{{ model.FLAG_DOG }}";
var flagDogDogCommandLink = "{{ model.FLAG_DOG_DOG_COMMAND_LINK }}";
var flagDragging = "dragging";
var flagDragOver = "drag-over";
var flagEdit = "{{ model.FLAG_EDIT }}";
var flagEmail = "{{ model.FLAG_EMAIL }}";
var flagError = "{{ model.FLAG_ERROR }}";
var flagExpanded = "{{ model.FLAG_EXPANDED }}";
var flagFailure = "{{ model.FLAG_FAILURE }}";
var flagFax = "{{ model.FLAG_FAX }}";
var flagFilter = "{{ model.FLAG_FILTER }}";
var flagForm = "{{ model.FLAG_FORM }}";
var flagFormFilters = "{{ model.FLAG_FORM_FILTERS }}";
var flagIcon = "{{ model.FLAG_ICON }}";
var flagImageLogo = "{{ model.FLAG_IMAGE_LOGO }}";
var flagInitialised = "{{ model.FLAG_INITIALISED }}";
var flagIsChecked = "{{ model.FLAG_IS_CHECKED }}";
var flagIsCollapsed = "{{ model.FLAG_IS_COLLAPSED }}";
var flagLeftHandStub = "{{ model.FLAG_LEFT_HAND_STUB }}";
var flagLightingLevel = "{{ model.FLAG_LIGHTING_LEVEL }}";
var flagLocation = "{{ model.FLAG_LOCATION }}";
var flagLocationParent = "{{ model.FLAG_LOCATION_PARENT }}";
var flagLogo = "{{ model.FLAG_LOGO }}";
var flagMessage = "{{ model.FLAG_MESSAGE }}";
var flagModal = "{{ model.FLAG_MODAL }}";
var flagMove = "move";
var flagName = "{{ model.FLAG_NAME }}";
var flagNameAttrOptionText = "{{ model.FLAG_NAME_ATTR_OPTION_TEXT}}";
var flagNameAttrOptionValue = "{{ model.FLAG_NAME_ATTR_OPTION_VALUE }}";
var flagNamePlural = "{{ model.FLAG_NAME_PLURAL }}";
var flagNavAdminHome = "{{ model.FLAG_NAV_ADMIN_HOME }}";
var flagNavContact = "{{ model.FLAG_NAV_CONTACT }}";
var flagNavHome = "{{ model.FLAG_NAV_HOME }}";
var flagNavDogAssessments = "{{ model.FLAG_NAV_DOG_ASSESSMENTS }}";
var flagNavDogButtonIcons = "{{ model.FLAG_NAV_DOG_BUTTON_ICONS }}";
var flagNavDogButtonShapes = "{{ model.FLAG_NAV_DOG_BUTTON_SHAPES }}";
var flagNavDogColour = "{{ model.FLAG_NAV_DOG_COLOUR }}";
var flagNavDogCommandButtonLinks = "{{ model.FLAG_NAV_DOG_COMMAND_BUTTON_LINKS }}";
var flagNavDogCommandCategories = "{{ model.FLAG_NAV_DOG_COMMAND_CATEGORIES }}";
var flagNavDogCommands = "{{ model.FLAG_NAV_DOG_COMMANDS }}";
var flagNavDogDogs = "{{ model.FLAG_NAV_DOG_DOGS }}";
var flagNavDogDogCommandLinks = "{{ model.FLAG_NAV_DOG_DOG_COMMAND_LINKS }}";
var flagNavDogHome = "{{ model.FLAG_NAV_DOG_HOME }}";
var flagNavDogLocations = "{{ model.FLAG_NAV_DOG_LOCATIONS }}";
var flagNavUserAccount = "{{ model.FLAG_NAV_USER_ACCOUNT }}";
var flagNavUserAdmin = "{{ model.FLAG_NAV_USER_ADMIN }}";
var flagNavUserLogin = "{{ model.FLAG_NAV_USER_LOGIN }}";
var flagNavUserLogout = "{{ model.FLAG_NAV_USER_LOGOUT }}";
var flagNotes = "{{ model.FLAG_NOTES }}";
var flagObedienceLevel = "{{ model.FLAG_OBEDIENCE_LEVEL }}";
var flagOverlay = "{{ model.FLAG_OVERLAY }}";
var flagOverlayClose = "{{ model.FLAG_OVERLAY_CLOSE }}";
var flagPageBody = "{{ model.FLAG_PAGE_BODY }}";
var flagPhoneNumber = "{{ model.FLAG_PHONE_NUMBER }}";
var flagPostcode = "{{ model.FLAG_POSTCODE }}";
var flagQuantity = "{{ model.FLAG_QUANTITY }}";
var flagResponseQualityMetric = "{{ model.FLAG_RESPONSE_QUALITY_METRIC }}";
var flagRightHandSide = "{{ model.FLAG_RIGHT_HAND_SIDE }}";
var flagRow = "{{ model.FLAG_ROW }}";
var flagRowNew = "{{ model.FLAG_ROW_NEW }}";
var flagRows = "{{ model.FLAG_ROWS }}";
var flagSave = "{{ model.FLAG_SAVE }}";
var flagScrollable = "{{ model.FLAG_SCROLLABLE }}";
var flagSearch = "{{ model.FLAG_SEARCH }}";
var flagSlider = "{{ model.FLAG_SLIDER }}";
var flagStatus = "{{ model.FLAG_STATUS }}";
var flagSubmit = "{{ model.FLAG_SUBMIT }}";
var flagSubmitted = "{{ model.FLAG_SUBMITTED }}";
var flagSuccess = "{{ model.FLAG_SUCCESS }}";
var flagTableMain = "{{ model.FLAG_TABLE_MAIN }}";
var flagTemporaryElement = "{{ model.FLAG_TEMPORARY_ELEMENT }}";
var flagUser = "{{ model.FLAG_USER }}";
var flagWeather = "{{ model.FLAG_WEATHER }}";
var flagWebsite = "{{ model.FLAG_WEBSITE }}";
var hashGetALTCHAChallenge = "{{ model.HASH_ALTCHA_CREATE_CHALLENGE }}";
var hashPageAccessibilityReport = "{{ model.HASH_PAGE_ACCESSIBILITY_REPORT }}";
var hashPageAccessibilityStatement = "{{ model.HASH_PAGE_ACCESSIBILITY_STATEMENT }}";
var hashPageAdminHome = "{{ model.HASH_PAGE_ADMIN_HOME }}";
var hashPageContact = "{{ model.HASH_PAGE_CONTACT }}";
var hashPageContactSuccess = "{{ model.HASH_PAGE_CONTACT_SUCCESS }}";
var hashPageDataRetentionSchedule = "{{ model.HASH_PAGE_DATA_RETENTION_SCHEDULE }}";
var hashPageDogAssessment = "{{ model.HASH_PAGE_DOG_ASSESSMENT }}";
var hashPageDogAssessments = "{{ model.HASH_PAGE_DOG_ASSESSMENTS }}";
var hashPageDogButtonIcons = "{{ model.HASH_PAGE_DOG_BUTTON_ICONS }}";
var hashPageDogButtonShapes = "{{ model.HASH_PAGE_DOG_BUTTON_SHAPES }}";
var hashPageDogColours = "{{ model.HASH_PAGE_DOG_COLOURS }}";
var hashPageDogCommandButtonLinks = "{{ model.HASH_PAGE_DOG_COMMAND_BUTTON_LINKS }}";
var hashPageDogCommandCategories = "{{ model.HASH_PAGE_DOG_COMMAND_CATEGORIES }}";
var hashPageDogCommands = "{{ model.HASH_PAGE_DOG_COMMANDS }}";
var hashPageDogDogCommandLinks = "{{ model.HASH_PAGE_DOG_DOG_COMMAND_LINKS }}";
var hashPageDogDogs = "{{ model.HASH_PAGE_DOG_DOGS }}";
var hashPageDogHome = "{{ model.HASH_PAGE_DOG_HOME }}";
var hashPageDogLocations = "{{ model.HASH_PAGE_DOG_LOCATIONS }}";
var hashPageErrorNoPermission = "{{ model.HASH_PAGE_ERROR_NO_PERMISSION }}";
var hashPageHome = "{{ model.HASH_PAGE_HOME }}";
var hashPageLicense = "{{ model.HASH_PAGE_LICENSE }}";
var hashPagePrivacyPolicy = "{{ model.HASH_PAGE_PRIVACY_POLICY }}";
var hashPageUserAccount = "{{ model.HASH_PAGE_USER_ACCOUNT }}";
var hashPageUserAdmin = "{{ model.HASH_PAGE_USER_ADMIN }}";
var hashPageUserLogin = "{{ model.HASH_PAGE_USER_LOGIN }}";
var hashPageUserLogout = "{{ model.HASH_PAGE_USER_LOGOUT }}";
var hashSaveDogAssessment = "{{ model.HASH_SAVE_DOG_ASSESSMENT }}";
var hashSaveDogButtonIcon = "{{ model.HASH_SAVE_DOG_BUTTON_ICON }}";
var hashSaveDogButtonShape = "{{ model.HASH_SAVE_DOG_BUTTON_SHAPE }}";
var hashSaveDogColour = "{{ model.HASH_SAVE_DOG_COLOUR }}";
var hashSaveDogCommand = "{{ model.HASH_SAVE_DOG_COMMAND }}";
var hashSaveDogCommandButtonLink = "{{ model.HASH_SAVE_DOG_COMMAND_BUTTON_LINK }}";
var hashSaveDogCommandCategory = "{{ model.HASH_SAVE_DOG_COMMAND_CATEGORY }}";
var hashSaveDogDogCommandLink = "{{ model.HASH_SAVE_DOG_DOG_COMMAND_LINK }}";
var hashSaveDogLocation = "{{ model.HASH_SAVE_DOG_LOCATION }}";
var idButtonApplyFilters = "#{{ model.ID_BUTTON_APPLY_FILTERS }}";
var idButtonHamburger = "#{{ model.ID_BUTTON_HAMBURGER }}";
var idButtonCancel = "#{{ model.ID_BUTTON_CANCEL }}";
var idButtonSave = "#{{ model.ID_BUTTON_SAVE }}";
var idContainerTemplateElements = "#{{ model.ID_CONTAINER_TEMPLATE_ELEMENTS }}";
var idCSRFToken = "#{{ model.ID_CSRF_TOKEN }}";
var idFormFilters = "#{{ model.ID_FORM_FILTERS }}";
var idLabelError = "#{{ model.ID_LABEL_ERROR }}";
var idOverlayConfirm = "#{{ model.ID_OVERLAY_CONFIRM }}";
var idOverlayError = "#{{ model.ID_OVERLAY_ERROR }}";
var idOverlayHamburger = "#{{ model.ID_OVERLAY_HAMBURGER }}";
var idPageBody = "#{{ model.ID_PAGE_BODY }}";
var idTableMain = "#{{ model.ID_TABLE_MAIN }}";
var idTextareaConfirm = "#{{ model.ID_TEXTAREA_CONFIRM }}";
var isUserLoggedIn = "{{ model.output_bool(model.IS_USER_LOGGED_IN) }}";
var _pathHost = "{{ model.get_url_host() }}";
var _rowBlank = null;
var titlePageCurrent = "{{ model.title }}";
var _verbose = ("{{ model.app.app_config.DEBUG }}" == "True");
</script>
<link rel="preload" as="style" href="{{ url_for('static', filename='dist/css/main.bundle.css') }}" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="{{ url_for('static', filename='dist/css/main.bundle.css') }}"></noscript>
{% block page_head %}{% endblock %}
</head>
<body data-page="{{ model.hash_page_current }}">
<!-- Header -- >
<header>
<div class="container">
<nav class="navbar">
<div class="{{ model.FLAG_LOGO }}" href="{{ model.HASH_PAGE_HOME }}">{{ model.NAME_COMPANY }}</div>
<div class="nav-links">
{% block page_nav_links %}{% endblock %}
</div>
</nav>
</div>
</header>
-->
<div class="topnav">
<div class="{{ model.FLAG_CONTAINER }} header-logo"> <!-- style="width: 18vw; min-width: 18vw; max-width: 20vw;" -->
<img class="header-logo" src="{{ url_for('static', filename='images/Wisp_LQ.webp') }}" alt="Fetch Metrics logo" aria-label="Fetch Metrics logo" tabindex="0">
</div>
<div class="{{ model.FLAG_CONTAINER }} company-name"> <!-- style="width: 75vw; min-width: 65vw; max-width: 80vw;" -->
<h1 class="company-name">{{ model.NAME_COMPANY_SHORT }} - {{ model.title }}</h1>
</div>
{#
<div class="{{ model.FLAG_CONTAINER }}"> <!-- style="width: 7vw; min-width: 7vw; max-width: 15vw; justify-content: flex-end; " padding-left: 25%; -->
<button id="{{ model.ID_BUTTON_HAMBURGER }}" class="{{ model.FLAG_BUTTON }} {{ model.FLAG_BUTTON_PRIMARY }}" tabindex="1" alt="Hamburger menu button" aria-label="Hamburger menu button"></button>
</div>
#}
</div>
<!-- Hamburger navigation menu -->
{% include 'components/common/buttons/_icon_hamburger.html' %}
<div id="{{ model.ID_OVERLAY_HAMBURGER }}" class="{{ model.FLAG_OVERLAY}} {{ model.FLAG_HAMBURGER }} {{ model.FLAG_IS_COLLAPSED }}">
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<a class="{{ model.FLAG_NAV_HOME }}">Home</a>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<a class="{{ model.FLAG_NAV_CONTACT }}">Contact</a>
</div>
{% if True or model.user.can_admin_dog %}
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<a class="{{ model.FLAG_NAV_DOG_HOME }}">Dog Home</a>
</div>
{% endif %}
{% if model.user.get_is_logged_in() %}
{#
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<a class="{{ model.FLAG_NAV_USER_ACCOUNT }}">Account</a>
</div>
#}
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<a class="{{ model.FLAG_NAV_USER_LOGOUT }}">Logout</a>
</div>
{% else %}
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<a class="{{ model.FLAG_NAV_USER_LOGIN }}">Login</a>
</div>
{% endif %}
</div>
<!-- Body -->
<div id="{{ model.ID_PAGE_BODY }}">
{% block page_body %}{% endblock %}
</div>
<!-- Footer -->
<div class="footer">
<h4>Copyright &copy; {{ model.NAME_COMPANY }}. <a href="{{ url_for('routes_legal.license') }}" alt="License" aria-label="License">All rights reserved.</a></h4>
<h5>Company number 13587499</h5>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}"><p><a href="{{ url_for('routes_legal.accessibility_statement') }}" alt="Accessibility statement" aria-label="Accessibility statement">Accessibility statement</a></p></div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}"><p><a href="{{ url_for('routes_legal.privacy_policy') }}" alt="Privacy notice" aria-label="Privacy notice">Privacy notice</a></p></div>
</div>
</div>
<script src="{{ url_for('static', filename='dist/js/main.bundle.js') }}"></script>
</body>
</html>

View File

@@ -0,0 +1,20 @@
<!-- v2a -->
{% extends 'layouts/layout.html' %}
{% block page_body %}
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/core_home.bundle.css') }}">
<div class="home-hero">
<h2 class="home-hero-title">Dog Training!</h2>
{% if not model.user.get_is_logged_in() %}
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<a class="{{ model.FLAG_NAV_USER_LOGIN }} {{ model.FLAG_BUTTON }} {{ model.FLAG_BUTTON_PRIMARY }}">Login</a>
</div>
{% elif True or model.user.can_admin_dog %}
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<a class="{{ model.FLAG_NAV_DOG_HOME }} {{ model.FLAG_BUTTON }} {{ model.FLAG_BUTTON_PRIMARY }}">Dog Home</a>
</div>
{% endif %}
</div>
{% endblock %}

View File

@@ -1,119 +0,0 @@
<!-- v2a -->
{% extends 'layouts/layout.html' %}
{% block page_head %}
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/core_home.bundle.css') }}">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/aos/2.3.4/aos.css">
{% endblock %}
{% block page_nav_links %}
<a href="#services">Services</a>
<a href="#testimonial">Testimonial</a>
<a href="#pricing">Pricing</a>
<a href="{{ model.HASH_PAGE_CONTACT }}" class="{{ model.FLAG_BUTTON }} {{ model.FLAG_BUTTON_PRIMARY }}">Contact Us</a>
{% endblock %}
{% block page_body %}
<section class="hero">
<div class="container">
<div class="hero-content" data-aos="fade-up">
<h1>Transform Your Business with Modern ERP Solutions</h1>
<p>UK-based ERPNext specialist providing integrated ERP and e-commerce solutions. 5+ years experience implementing systems for builders merchants and automotive companies.</p>
<a href="{{ model.HASH_PAGE_CONTACT }}" class="{{ model.FLAG_BUTTON }} {{ model.FLAG_BUTTON_PRIMARY }}">Book Consultation</a>
</div>
</div>
</section>
<section id="services" class="services">
<div class="container">
<h2 class="section-title text-center">Our Services</h2>
<p class="section-subtitle text-center">Comprehensive ERP solutions tailored to your business needs</p>
<div class="services-grid">
<div class="service-card" data-aos="fade-up" data-aos-delay="100">
<h3>Implementation Services</h3>
<p>Full ERPNext implementation including setup, configuration, and training. We ensure a smooth transition to your new ERP system.</p>
</div>
<div class="service-card" data-aos="fade-up" data-aos-delay="200">
<h3>Integration & Migration</h3>
<p>Seamlessly migrate your existing data and integrate ERPNext with your current business applications and workflows.</p>
</div>
<div class="service-card" data-aos="fade-up" data-aos-delay="300">
<h3>Hosting Services</h3>
<p>Secure, reliable cloud hosting with regular backups and maintenance to keep your ERP system running smoothly.</p>
</div>
<div class="service-card" data-aos="fade-up" data-aos-delay="400">
<h3>Custom Extensions</h3>
<p>Tailored app development and customizations to extend ERPNext functionality according to your specific requirements.</p>
</div>
</div>
</div>
</section>
{#
<section id="testimonial" class="testimonial">
<div class="container">
<h2 class="section-title text-center">Client Success Story</h2>
<p class="section-subtitle text-center">See how we've helped other businesses succeed</p>
<div class="testimonial-card" data-aos="fade-up">
<p>"The ERPNext implementation has revolutionized our operations. The integrated e-commerce system has streamlined our entire sales process, and the team's support has been exceptional throughout our journey."</p>
<p><strong>- 4 Shires Builders Merchants</strong></p>
</div>
</div>
</section>
#}
<section id="pricing" class="pricing">
<div class="container">
<h2 class="section-title text-center">Simple, Transparent Pricing</h2>
<p class="section-subtitle text-center">Enterprise-grade solutions at SMB-friendly prices</p>
<div class="pricing-card" data-aos="fade-up">
<h3>Implementation</h3>
<div class="price">From £10,000</div>
<p>One-time setup fee based on business size</p>
<ul style="list-style: none; margin: 2rem 0;">
<li>✓ Full ERP & e-commerce setup</li>
<li>✓ Product catalogue configuration</li>
<li>✓ Staff training</li>
<li>✓ Data migration</li>
</ul>
<h3>Monthly Support & Hosting</h3>
<div class="price">£200</div>
<p>12-month minimum term, billed annually at £2,400</p>
<ul style="list-style: none; margin: 2rem 0;">
<li>✓ Unlimited support tickets</li>
<li>✓ Cloud hosting (99.9% uptime)</li>
<li>✓ Regular maintenance and system updates</li>
</ul>
<a href="{{ model.HASH_PAGE_CONTACT }}" class="{{ model.FLAG_BUTTON }} {{ model.FLAG_BUTTON_PRIMARY }}">Get Custom Quote</a>
</div>
</div>
</section>
<section class="cta">
<div class="container">
<h2 class="section-title">Ready to Transform Your Business?</h2>
<p class="section-subtitle">Contact us today to discuss your ERP needs</p>
<a href="{{ model.HASH_PAGE_CONTACT }}" class="{{ model.FLAG_BUTTON }} {{ model.FLAG_BUTTON_LIGHT }}">Book Consultation</a>
</div>
</section>
<!-- CDN -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/aos/2.3.4/aos.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
AOS.init({
duration: 1000,
once: true
});
});
</script>
{% endblock %}

View File

@@ -0,0 +1,77 @@
{% extends 'layouts/layout.html' %}
{% block page_head %}
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/core_contact.bundle.css') }}">
{% endblock %}
{% block page_nav_links %}
{#
<a href="#contact-form">Contact Form</a>
<a href="#contact-details">Contact Details</a>
#}
{% endblock %}
{% block page_body %}
{% set form = model.form_contact %}
<section class="contact-section">
<div class="contact-form">
<h1>Contact Us</h1>
<p>Please fill in the form below and we'll get back to you as soon as possible.</p>
<form id="{{ model.ID_CONTACT_FORM }}" method="POST" action="{{ model.HASH_POST_CONTACT_FORM }}">
{{ form.csrf_token }}
<div class="form-grid">
<label class="form-label" for="{{ form.email.id }}">{{ form.email.label.text }} *</label>
<div>
{{ form.email(class="form-input", required=True) }}
</div>
<label class="form-label" for="{{ form.contact_name.id }}">{{ form.contact_name.label.text }} *</label>
<div>
{{ form.contact_name(class="form-input", required=True) }}
</div>
<label class="form-label" for="{{ form.company_name.id }}">{{ form.company_name.label.text }} *</label>
<div>
{{ form.company_name(class="form-input", required=True) }}
</div>
<label class="form-label" for="{{ form.message.id }}">{{ form.message.label.text }} *</label>
<div>
{{ form.message(class="form-input", required=True) }}
</div>
</div>
<div class="{{ model.FLAG_CONTAINER_CHECKBOX }} {{ model.FLAG_RECEIVE_MARKETING }} marketing-consent">
{{ model.form_contact.receive_marketing() }}
{{ model.form_contact.receive_marketing.label }}
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_CAPTCHA }}">
<div>
{{ form.altcha.label }}
<altcha-widget
class="altcha-widget"
challengeurl="{{ model.HASH_GET_ALTCHA_CHALLENGE }}"
auto="onload"
id="{{ form.altcha.id }}"
name="{{ form.altcha.name }}"
></altcha-widget>
</div>
<p>This CAPTCHA mechanism is fully GDPR-compliant with no cookies, no fingerprinting, no tracking, and runs in the background so you don't need to do anything!</p>
</div>
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{{ model.form_contact.submit() }}
</div>
</form>
<div class="data-notice">
<h3>How we use your information</h3>
<p>If you opt in to marketing communications, we will also use your email address to send you updates about our services, ERPNext features, and relevant industry news. You can unsubscribe from these communications at any time.</p>
<p>We retain contact form submissions for customer service purposes and retain marketing consent records as required by law. For details about how long we keep your information, please see our <a href="{{ model.HASH_PAGE_DATA_RETENTION_SCHEDULE }}">data retention schedule</a>.</p>
<p>For full details about how we handle your personal data, please read our <a href="{{ model.HASH_PAGE_PRIVACY_POLICY }}">Privacy Policy</a>.</p>
</div>
</div>
</section>
{% endblock %}

View File

@@ -0,0 +1,22 @@
{% extends 'layouts/layout.html' %}
{% block page_head %}
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/core_contact.bundle.css') }}">
{% endblock %}
{% block page_nav_links %}
{% endblock %}
{% block page_body %}
{% set form = model.form_contact %}
<section class="contact-section">
<div class="contact-form">
<h1>Message Received</h1>
<p>Thanks for contacting us! We've received your message and will respond within 48 hours.</p>
</div>
</section>
<script>
</script>
{% endblock %}

View File

@@ -2,19 +2,240 @@
{% extends 'layouts/layout.html' %} {% extends 'layouts/layout.html' %}
{% block page_body %} {% block page_head %}
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/core_home.bundle.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='dist/css/core_home.bundle.css') }}">
<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/aos/2.3.4/aos.css"> -->
{% endblock %}
<div class="home-hero"> {% block page_nav_links %}
<h2 class="home-hero-title">Dog Training!</h2> <a href="#{{ model.FLAG_PROBLEM }}">Problem</a>
{% if not model.user.get_is_logged_in() %} <a href="#{{ model.FLAG_SOLUTION }}">Solution</a>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}"> <a href="#{{ model.FLAG_BENEFITS }}">Benefits</a>
<a class="{{ model.FLAG_NAV_USER_LOGIN }} {{ model.FLAG_BUTTON }} {{ model.FLAG_BUTTON_PRIMARY }}">Login</a> <a href="#{{ model.FLAG_SOCIAL_PROOF }}">Social Proof</a>
<!-- <a href="#{{ model.FLAG_EARLY_ACCESS }}">Early Access</a> -->
<a href="#{{ model.FLAG_FEATURES }}">Features</a>
<a href="#{{ model.FLAG_FAQ }}">FAQs</a>
<a href="{{ model.HASH_PAGE_CONTACT }}" class="{{ model.FLAG_BUTTON }} {{ model.FLAG_BUTTON_PRIMARY }}">Contact Us</a>
{% endblock %}
{% block page_body %}
<section class="hero">
<div class="container">
<div class="hero-content" data-aos="fade-up">
<h1>Track Every Tail Wag of Progress</h1>
<p>The UK's first professional dog training management platform that transforms how you document, measure, and showcase training success!</p>
<a href="{{ model.HASH_PAGE_CONTACT }}" class="{{ model.FLAG_BUTTON }} {{ model.FLAG_BUTTON_PRIMARY }}">Get Early Access</a>
<!-- <a href="{{ model.HASH_PAGE_CONTACT }}" class="{{ model.FLAG_BUTTON }} {{ model.FLAG_BUTTON_PRIMARY }}">Watch 2-Minute Demo</a> -->
</div> </div>
{% elif True or model.user.can_admin_dog %} </div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}"> </section>
<a class="{{ model.FLAG_NAV_DOG_HOME }} {{ model.FLAG_BUTTON }} {{ model.FLAG_BUTTON_PRIMARY }}">Dog Home</a>
<!--
<section id="{{ model.FLAG_PROBLEM_SOLUTION }}" class="{{ model.FLAG_PROBLEM_SOLUTION }}">
<div class="container">
<h2 class="section-title text-center">Finally, Software That Understands Dog Training</h2>
<p class="section-subtitle text-center"><strong>Problem Statement:</strong> Running a dog training business shouldn't mean drowning in paperwork. Between managing client schedules, tracking each dog's progress, sending updates to worried pet parents, and keeping your business profitable, there's barely time left for actual training.</p>
<p class="section-subtitle text-center"><strong>Solution Overview:</strong> Fetch Metrics was built specifically for dog trainers by people who understand your industry. Every feature is designed around how you actually work - from intake forms that capture behavioral quirks to progress reports that build client confidence.</p>
<p>Key features:</p>
<ul> < !-- style="list-style: none; margin: 2rem 0;"-- >
<li>✓ <strong>Client & Dog Management:</strong> Complete profiles with photos, medical notes, and behavioral history</li>
<li>✓ <strong>Session Tracking:</strong> Quick note-taking, homework assignments, and progress photos</li>
</ul>
</div>
</section>
-->
<section id="{{ model.FLAG_PROBLEM }}" class="{{ model.FLAG_PROBLEM }}">
<div class="container">
<h2 class="section-title text-center">Still Using Spreadsheets and Paper Notes?</h2>
<!--
<p class="section-subtitle text-center"><strong>Problem Statement:</strong> Running a dog training business shouldn't mean drowning in paperwork. Between managing client schedules, tracking each dog's progress, sending updates to worried pet parents, and keeping your business profitable, there's barely time left for actual training.</p>
<p class="section-subtitle text-center"><strong>Solution Overview:</strong> Fetch Metrics was built specifically for dog trainers by people who understand your industry. Every feature is designed around how you actually work - from intake forms that capture behavioral quirks to progress reports that build client confidence.</p>
<div class="{{ model.FLAG_CARD }} {{ model.FLAG_PROBLEM }}">
<p class="section-subtitle text-center">Pain Points:</p>
<ul> < !-- style="list-style: none; margin: 2rem 0;"-- >
<li>Spending 10+ hours per week on paperwork and scheduling</li>
<li>Losing client information in messy spreadsheets</li>
<li>Forgetting to follow up on training progress</li>
<li>Struggling to show clients their dog's improvement</li>
<li>Missing appointments and double-booking sessions</li>
<li>Difficulty tracking payments and outstanding invoices</li>
</ul>
<p>You became a dog trainer to work with animals and help families - not to be a data entry clerk. Yet successful trainers tell us they spend more time on administration than actual training.</p>
</div> </div>
{% endif %} -->
</div> <div class="{{ model.FLAG_CARD }} {{ model.FLAG_PROBLEM }}">
<p>You're not alone. Most UK dog trainers spend hours each week juggling multiple systems, trying to remember which dog knows which commands, and struggling to show clients real progress.</p>
<p>What if you could track every command, every session, and every breakthrough in one simple system?</p>
</div>
</div>
</section>
<section id="{{ model.FLAG_SOLUTION }}" class="{{ model.FLAG_SOLUTION }}">
<div class="container">
<h2 class="section-title text-center">Professional Progress Tracking Made Simple</h2>
<!--
<p class="section-subtitle text-center"><strong>Problem Statement:</strong> Running a dog training business shouldn't mean drowning in paperwork. Between managing client schedules, tracking each dog's progress, sending updates to worried pet parents, and keeping your business profitable, there's barely time left for actual training.</p>
<p class="section-subtitle text-center"><strong>Solution Overview:</strong> Fetch Metrics was built specifically for dog trainers by people who understand your industry. Every feature is designed around how you actually work - from intake forms that capture behavioral quirks to progress reports that build client confidence.</p>
<div class="{{ model.FLAG_CARD }} {{ model.FLAG_SOLUTION }}">
<p class="section-subtitle text-center">Teaser Benefits:</p>
<ul>
<li><strong>Professional Client Management:</strong> Never lose track of a client or their dog's progress again</li>
<li><strong>Effortless Scheduling:</strong> Appointments that actually sync with your life</li>
<li><strong>Progress That Speaks:</strong> Show clients exactly how their dog is improving</li>
<li><strong>Smart Business Tools:</strong> Everything you need to run a professional training business</li>
<li><strong>Happy Dog Owners:</strong> Give clients access to their dog's training journey</li>
</ul>
<p><strong>Note:</strong> Full feature details available to beta users only</p>
</div>
-->
<p class="section-subtitle text-center">Finally, a system built specifically for how dog trainers actually work. Document command mastery, track skill progression, and generate professional progress reports that wow your clients.</p>
<div class="{{ model.FLAG_CARD }} {{ model.FLAG_SOLUTION }}">
<ul>
<li><strong>Command Performance Tracking:</strong> Monitor success rates for every command, from basic sit-stay to advanced behaviours</li>
<li><strong>Skill Level Assessment:</strong> Automatically track progression through training levels with detailed performance metrics</li>
<li><strong>Professional Progress Reports:</strong> Generate impressive client reports that showcase real, measurable improvement</li>
<li><strong>Session History:</strong> Never lose track of what you worked on last week or which exercises need reinforcement</li>
</ul>
</div>
</div>
</section>
<section id="{{ model.FLAG_BENEFITS }}" class="{{ model.FLAG_BENEFITS }}">
<div class="container">
<h2 class="section-title text-center">More Than Just Software - It's Your Training Partner</h2>
<div class="{{ model.FLAG_CARD }} {{ model.FLAG_BENEFITS }}">
<p class="section-subtitle text-center">For Your Business:</p>
<ul>
<li>✓ Reduce admin time by 70% with automated progress tracking</li>
<li>✓ Increase client retention with professional progress reports</li>
<li>✓ Stand out from competitors with data-driven training insights</li>
</ul>
<p class="section-subtitle text-center">For Your Clients:</p>
<ul>
<li>✓ See their dog's journey from first sit to graduation</li>
<li>✓ Understand exactly what their dog has mastered</li>
<li>✓ Feel confident in your professional approach</li>
</ul>
<p class="section-subtitle text-center">For Your Dogs:</p>
<ul>
<li>✓ Consistent training approach across all sessions</li>
<li>✓ Targeted practice on areas that need work</li>
<li>✓ Faster progression through structured tracking</li>
</ul>
</div>
</div>
</section>
<section id="{{ model.FLAG_SOCIAL_PROOF }}" class="{{ model.FLAG_SOCIAL_PROOF }}">
<div class="container">
<h2 class="section-title text-center">Join Progressive UK Trainers Already Transforming Their Business</h2>
<div class="{{ model.FLAG_CARD }} {{ model.FLAG_SOCIAL_PROOF }}">
<p class="section-subtitle text-center">
"I wish I'd had this 5 years ago. What used to take me a full Sunday afternoon now takes 20 minutes. My clients love seeing their dog's progress, and I actually enjoy the business side now."
<ul>
<li>Tierney G., Dog Trainer, Rugby</li>
</ul>
</p>
<!--
<p class="section-subtitle text-center">Stats:</p>
<ul>
<li>✓ 30+ Professional Trainers in Beta</li>
<li>✓ 500+ Dogs Successfully Tracked</li>
<li>✓ 10 Hours Saved Per Week (Average)</li>
<li>✓ 40% Increase in Client Retention</li>
</ul>
-->
</div>
</div>
</section>
<section id="{{ model.FLAG_FEATURES }}" class="{{ model.FLAG_FEATURES }}">
<div class="container">
<h2 class="section-title text-center">Everything You Need to Run a Modern Training Business</h2>
<div class="{{ model.FLAG_CARD }} {{ model.FLAG_FEATURES }}">
<ul>
<li>✓ Detailed command performance tracking</li>
<li>✓ Multi-level skill progression monitoring</li>
<li>✓ Professional progress report generation</li>
<li>✓ Client and dog profile management</li>
<li>✓ Session planning and note-taking</li>
<li>✓ Mobile-friendly for field use</li>
<li>✓ Secure cloud-based storage</li>
<li>✓ GDPR compliant</li>
</ul>
<a href="{{ model.HASH_PAGE_CONTACT }}" class="{{ model.FLAG_BUTTON }} {{ model.FLAG_BUTTON_PRIMARY }}">Reserve Your Spot Now</a>
<p>30-day money-back guarantee • Cancel anytime • No setup fees</p>
</div>
</div>
</section>
<!--
<section id="{{ model.FLAG_EARLY_ACCESS }}" class="{{ model.FLAG_EARLY_ACCESS }}">
<div class="container">
<h2 class="section-title text-center">Be Among the First to Experience the Future of Dog Training Business Management</h2>
<p class="section-subtitle text-center">Limited early access launching Autumn 2025. Join successful trainers who are already seeing results.</p>
<div class="{{ model.FLAG_CARD }} {{ model.FLAG_EARLY_ACCESS }}">
<p class="section-subtitle text-center">What You Get:</p>
<ul>
<li>✓ First access when we launch</li>
<li>✓ Exclusive beta features</li>
<li>✓ Direct input on development</li>
<li>✓ Founding member pricing (save 50% for life)</li>
<li>✓ Personal onboarding session</li>
</ul>
<a href="{{ model.HASH_PAGE_CONTACT }}" class="{{ model.FLAG_BUTTON }} {{ model.FLAG_BUTTON_PRIMARY }}">Reserve Your Spot Now</a>
<p class="section-subtitle text-center"><strong>Risk Reversal:</strong> 30-day money-back guarantee • Cancel anytime • No setup fees</p>
</div>
</div>
</section>
-->
<section class="{{ model.FLAG_CTA_1 }}">
<div class="container">
<h2 class="section-title">Ready to Revolutionise Your Training Business?</h2>
<p class="section-subtitle text-center">Join the waitlist for early access to the UK's most comprehensive dog training management platform.</p>
<a href="{{ model.HASH_PAGE_CONTACT }}" class="{{ model.FLAG_BUTTON }} {{ model.FLAG_BUTTON_LIGHT }}">Get Early Access Today</a>
<p>30-day money-back guarantee • Cancel anytime • No setup fees</p>
</div>
</section>
<section id="{{ model.FLAG_FAQ }}" class="{{ model.FLAG_FAQ }}">
<div class="container">
<h2 class="section-title text-center">FAQs</h2>
<div class="{{ model.FLAG_CARD }} {{ model.FLAG_FAQ }}">
<ul>
<li><strong>Q: Is this just another scheduling app?:</strong> A: No, we're focused on what matters most - tracking and showcasing training progress. While we include scheduling features, our core strength is detailed command performance tracking and professional reporting.</li>
<li><strong>Q: Do my clients need their own accounts?:</strong> A: That's up to you! You can generate reports to share, or give clients access to view their dog's progress directly.</li>
<li><strong>Q: How detailed is the progress tracking?:</strong> A: As detailed as you need. Track success rates, duration, distractions, environments, and more for every command and behaviour.</li>
<li><strong>Q: Will this work for my training style?:</strong> A: Built by trainers, for trainers. Whether you use positive reinforcement, balanced training, or specialised techniques, our flexible system adapts to you.</li>
</ul>
</div>
</div>
</section>
<section class="{{ model.FLAG_CTA_2 }}">
<div class="container">
<h2 class="section-title">Stop Losing Track of Training Progress</h2>
<p class="section-subtitle text-center">Your expertise deserves professional tools. Join innovative UK trainers who are already transforming how they track, measure, and showcase training success.</p>
<a href="{{ model.HASH_PAGE_CONTACT }}" class="{{ model.FLAG_BUTTON }} {{ model.FLAG_BUTTON_LIGHT }}">Join the Waitlist</a>
<p>Enter your email for updates and exclusive early access</p>
</div>
</section>
<!-- CDN -- >
<script src="https://cdnjs.cloudflare.com/ajax/libs/aos/2.3.4/aos.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
AOS.init({
duration: 1000,
once: true
});
});
</script>
-->
{% endblock %} {% endblock %}

View File

@@ -1,4 +1,4 @@
{% extends 'layouts/layout.html' %} {% extends 'layouts/layout_dog.html' %}
{% block page_body %} {% block page_body %}
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/dog_assessment.bundle.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='dist/css/dog_assessment.bundle.css') }}">

View File

@@ -1,4 +1,4 @@
{% extends 'layouts/layout.html' %} {% extends 'layouts/layout_dog.html' %}
{% block page_body %} {% block page_body %}
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/dog_assessments.bundle.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='dist/css/dog_assessments.bundle.css') }}">

View File

@@ -1,4 +1,4 @@
{% extends 'layouts/layout.html' %} {% extends 'layouts/layout_dog.html' %}
{% block page_body %} {% block page_body %}
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/dog_button_icons.bundle.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='dist/css/dog_button_icons.bundle.css') }}">

View File

@@ -1,4 +1,4 @@
{% extends 'layouts/layout.html' %} {% extends 'layouts/layout_dog.html' %}
{% block page_body %} {% block page_body %}
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/dog_command_button_links.bundle.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='dist/css/dog_command_button_links.bundle.css') }}">

View File

@@ -1,4 +1,4 @@
{% extends 'layouts/layout.html' %} {% extends 'layouts/layout_dog.html' %}
{% block page_body %} {% block page_body %}
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/dog_command_categories.bundle.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='dist/css/dog_command_categories.bundle.css') }}">

View File

@@ -1,4 +1,4 @@
{% extends 'layouts/layout.html' %} {% extends 'layouts/layout_dog.html' %}
{% block page_body %} {% block page_body %}
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/dog_commands.bundle.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='dist/css/dog_commands.bundle.css') }}">

View File

@@ -1,4 +1,4 @@
{% extends 'layouts/layout.html' %} {% extends 'layouts/layout_dog.html' %}
{% block page_body %} {% block page_body %}
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/dog_dog_command_links.bundle.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='dist/css/dog_dog_command_links.bundle.css') }}">

View File

@@ -1,4 +1,4 @@
{% extends 'layouts/layout.html' %} {% extends 'layouts/layout_dog.html' %}
{% block title %}{{ model.title }}{% endblock %} {% block title %}{{ model.title }}{% endblock %}

View File

@@ -1,4 +1,4 @@
{% extends 'layouts/layout.html' %} {% extends 'layouts/layout_dog.html' %}
{% block page_body %} {% block page_body %}
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/dog_locations.bundle.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='dist/css/dog_locations.bundle.css') }}">

View File

@@ -24,6 +24,7 @@ Features:
- Add Is_Handler field to User table and filters - Add Is_Handler field to User table and filters
- Add Is_Default field to all Lookup tables - Add Is_Default field to all Lookup tables
- Response Quality Metric - add field bigger value measured is better? - Response Quality Metric - add field bigger value measured is better?
- Permissions
Fix: Fix:

View File

@@ -29,8 +29,12 @@ module.exports = {
], ],
// Core // Core
core_home: [ core_home: [
path.resolve(__dirname, 'static/css/sections/core.css'), path.resolve(__dirname, 'static/css/sections/core.css'),
path.resolve(__dirname, 'static/css/pages/core/home.css') path.resolve(__dirname, 'static/css/pages/core/home.css')
],
core_contact: [
path.resolve(__dirname, 'static/css/sections/core.css'),
path.resolve(__dirname, 'static/css/pages/core/contact.css')
], ],
core_admin_home: [ core_admin_home: [
path.resolve(__dirname, 'static/css/sections/core.css'), path.resolve(__dirname, 'static/css/sections/core.css'),