Initial commit

This commit is contained in:
2025-03-06 10:51:12 -06:00
parent 2737ca7241
commit cdb3c1b771
88 changed files with 35964 additions and 0 deletions

View File

View File

@@ -0,0 +1,16 @@
"""
ASGI config for company_site project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.0/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'company_site.settings')
application = get_asgi_application()

View File

@@ -0,0 +1,149 @@
"""
Django settings for company_site project.
Generated by 'django-admin startproject' using Django 5.0.
For more information on this file, see
https://docs.djangoproject.com/en/5.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.0/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-0$+hho_6%-(ud^t%0zos(q&i@2&)9m+u&dgj77&51g$m#hr^0s'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ["*"]
# Application definition
INSTALLED_APPS = [
'public.apps.PublicConfig',
'financial.apps.FinancialConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'phonenumber_field',
'django_recaptcha',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'company_site.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'company_site.wsgi.application'
# Database
# https://docs.djangoproject.com/en/5.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/5.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.0/howto/static-files/
STATIC_URL = 'static/'
# Default primary key field type
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# # email settings
# EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# EMAIL_USE_TLS = True
# EMAIL_HOST = 'smtp.outlook.office365.com'#'smtp-mail.outlook.com'
# EMAIL_HOST_USERNAME = 'ryan@aimloperations.com'
# EMAIL_HOST_USER = 'ryan@aimloperations.com'
# EMAIL_HOST_PASSWORD = '!HopeThisW0rkz'
# EMAIL_PORT = 587
# SERVER_EMAIL = EMAIL_HOST_USER
# Recapcha Stuff
RECAPTCHA_PUBLIC_KEY = '6LdXRbopAAAAAL9NT7C2J3Fuu_b6rvhhsPyxTd9Z'
RECAPTCHA_PRIVATE_KEY = '6LdXRbopAAAAAPt31zdQJaOwLseognmZHZEHmWlt'
# SMTP2GO
EMAIL_HOST = 'mail.smtp2go.com'
EMAIL_HOST_USER = 'info.aimloperations.com'
EMAIL_HOST_PASSWORD = 'ZDErIII2sipNNVMz'
EMAIL_PORT = 2525
EMAIL_USE_TLS = True

View File

@@ -0,0 +1,25 @@
"""
URL configuration for company_site project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path("public/", include("public.urls")),
path("financial/", include("financial.urls")),
path('admin/', admin.site.urls),
]

View File

@@ -0,0 +1,16 @@
"""
WSGI config for company_site project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.0/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'company_site.settings')
application = get_wsgi_application()

View File

View File

@@ -0,0 +1,8 @@
from django.contrib import admin
from .models import Contract
# Register your models here.
class ContractAdmin(admin.ModelAdmin):
pass
admin.site.register(Contract, ContractAdmin)

View File

@@ -0,0 +1,6 @@
from django.apps import AppConfig
class FinancialConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'financial'

View File

@@ -0,0 +1,20 @@
from django import forms
from django.forms import ModelForm
from .models import Employee, Contract, ChargeNumber
class EmployeeForm(ModelForm):
class Meta:
model = Employee
# TODO: fix slary to be salary
fields = ["primaryAddress","workAddress", "slary"]
class ContractForm(ModelForm):
class Meta:
model = Contract
fields = ["contract_type","name","proposed_amount","baseline_amount","funded_amount","baseline_start","baseline_end"]
class ChargeNumberForm(ModelForm):
class Meta:
model = ChargeNumber
fields = ["charge_number_type","amount", "start_date","end_date"]

View File

@@ -0,0 +1,120 @@
# Generated by Django 5.0 on 2024-02-11 20:29
import django.db.models.deletion
import django.utils.timezone
import django_enum.fields
import phonenumber_field.modelfields
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='AddressModel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('address_1', models.CharField(max_length=128)),
('address_2', models.CharField(blank=True, max_length=128)),
('city', models.CharField(max_length=64)),
('state', models.CharField(max_length=2)),
('zip_code', models.CharField(max_length=5)),
],
),
migrations.CreateModel(
name='Contract',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateTimeField(default=django.utils.timezone.now)),
('last_modified', models.DateTimeField(default=django.utils.timezone.now)),
('slug', models.SlugField()),
('contract_type', django_enum.fields.EnumCharField(choices=[('FFP', 'FIRM_FIX_PRICED'), ('MAX', 'MAX_NUM_CONTRACT_TYPES')], max_length=3)),
('name', models.CharField(max_length=100)),
('proposed_amount', models.FloatField(default=0.0)),
('baseline_amount', models.FloatField(default=0.0)),
('funded_amount', models.FloatField(default=0.0)),
('baseline_start', models.DateField(default=None, null=True)),
('baseline_end', models.DateField(default=None, null=True)),
('linkedContracts', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='financial.contract')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='ChargeNumber',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateTimeField(default=django.utils.timezone.now)),
('last_modified', models.DateTimeField(default=django.utils.timezone.now)),
('slug', models.SlugField()),
('charge_number_type', django_enum.fields.EnumCharField(choices=[('LOE', 'LEVEL_OF_EFFORT'), ('QBD', 'QBD'), ('0_100', 'ZERO_ONE_HUNDRED'), ('50_50', 'FIFTY_FIFTY'), ('MAX', 'MAX_NUM_TASK_TYPES')], max_length=5)),
('amount', models.FloatField(default=0.0)),
('percent_complete', models.FloatField(default=0.0)),
('startDate', models.DateField(default=None, null=True)),
('endDate', models.DateField(default=None, null=True)),
('contract', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='financial.contract')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='Employee',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateTimeField(default=django.utils.timezone.now)),
('last_modified', models.DateTimeField(default=django.utils.timezone.now)),
('slug', models.SlugField()),
('phoneNumber', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region=None, unique=True)),
('slary', models.FloatField(default=0.0)),
('manager', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='manager_employee', to='financial.employee')),
('primaryAddress', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='primary_address_employee', to='financial.addressmodel')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
('workAddress', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='work_address_employee', to='financial.addressmodel')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='TimeCard',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateTimeField(default=django.utils.timezone.now)),
('last_modified', models.DateTimeField(default=django.utils.timezone.now)),
('slug', models.SlugField()),
('startDate', models.DateField(default=None, null=True)),
('endDate', models.DateField(default=None, null=True)),
('approvedDate', models.DateField(default=None, null=True)),
('approvalComment', models.TextField(default='', max_length=256)),
('approvedBy', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='approved_by', to='financial.employee')),
('employee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='employee', to='financial.employee')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='TimeCardCell',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateTimeField(default=django.utils.timezone.now)),
('last_modified', models.DateTimeField(default=django.utils.timezone.now)),
('slug', models.SlugField()),
('date', models.DateField(default=None, null=True)),
('hour', models.FloatField(default=0.0)),
('timeCard', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='financial.timecard')),
],
options={
'abstract': False,
},
),
]

View File

@@ -0,0 +1,23 @@
# Generated by Django 5.0 on 2024-02-12 21:27
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('financial', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='contract',
name='baseline_end',
field=models.DateField(blank=True, default=None, null=True),
),
migrations.AlterField(
model_name='contract',
name='baseline_start',
field=models.DateField(blank=True, default=None, null=True),
),
]

View File

@@ -0,0 +1,19 @@
# Generated by Django 5.0 on 2024-02-13 14:02
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('financial', '0002_alter_contract_baseline_end_and_more'),
]
operations = [
migrations.AlterField(
model_name='contract',
name='linkedContracts',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='financial.contract'),
),
]

View File

@@ -0,0 +1,31 @@
# Generated by Django 5.0 on 2024-02-13 14:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('financial', '0003_alter_contract_linkedcontracts'),
]
operations = [
migrations.RemoveField(
model_name='chargenumber',
name='endDate',
),
migrations.RemoveField(
model_name='chargenumber',
name='startDate',
),
migrations.AddField(
model_name='chargenumber',
name='end_date',
field=models.DateField(blank=True, default=None, null=True),
),
migrations.AddField(
model_name='chargenumber',
name='start_date',
field=models.DateField(blank=True, default=None, null=True),
),
]

View File

@@ -0,0 +1,29 @@
# Generated by Django 4.2.17 on 2025-02-10 17:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("financial", "0004_remove_chargenumber_enddate_and_more"),
]
operations = [
migrations.AddConstraint(
model_name="chargenumber",
constraint=models.CheckConstraint(
check=models.Q(
("charge_number_type__in", ["LOE", "QBD", "0_100", "50_50", "MAX"])
),
name="financial_ChargeNumber_charge_number_type_ChargeNumberTypeEnum",
),
),
migrations.AddConstraint(
model_name="contract",
constraint=models.CheckConstraint(
check=models.Q(("contract_type__in", ["FFP", "MAX"])),
name="financial_Contract_contract_type_ContractTypeEnum",
),
),
]

View File

@@ -0,0 +1,105 @@
from django.db import models
from django.contrib.auth.models import User
from phonenumber_field.modelfields import PhoneNumberField
from django.utils import timezone
from django_enum import EnumField
from django.utils.text import slugify
import datetime
# Abstract Model Classes
class TimeMixin(models.Model):
created = models.DateTimeField(default=timezone.now)
last_modified = models.DateTimeField(default=timezone.now)
created_by = models.ForeignKey
last_modified_BY = models.ForeignKey
class Meta:
abstract = True
class IdMixin(models.Model):
slug = models.SlugField()
class Meta:
abstract = True
def save(self, *args, **kwargs):
if self.slug is None:
self.slug = slugify(datetime.datetime.now().time())
super(IdMixin, self).save(*args, **kwargs)
# Concrete Classes
class Contract(IdMixin, TimeMixin):
class ContractTypeEnum(models.TextChoices):
FIRM_FIX_PRICED = "FFP", "FIRM_FIX_PRICED"
MAX_NUM_CONRACT_TYPES = "MAX", "MAX_NUM_CONTRACT_TYPES"
contract_type = EnumField(ContractTypeEnum)
name = models.CharField(max_length=100)
proposed_amount = models.FloatField(default=0.0)
baseline_amount = models.FloatField(default=0.0)
funded_amount = models.FloatField(default=0.0)
baseline_start = models.DateField(null=True, blank=True, default=None)
baseline_end = models.DateField(null=True, blank=True, default=None)
linkedContracts = models.ForeignKey("self", on_delete=models.CASCADE, null=True, blank=True)
# TODO: make calc ev func
class ChargeNumber(IdMixin, TimeMixin):
class ChargeNumberTypeEnum(models.TextChoices):
LEVEL_OF_EFFORT = "LOE", "LEVEL_OF_EFFORT"
QBD = "QBD", "QBD"
ZERO_ONE_HUNDRED = "0_100", "ZERO_ONE_HUNDRED"
FIFTY_FIFTY = "50_50", "FIFTY_FIFTY"
MAX_NUM_TASK_TYPES = "MAX", "MAX_NUM_TASK_TYPES"
charge_number_type = EnumField(ChargeNumberTypeEnum)
contract = models.ForeignKey(Contract, on_delete=models.CASCADE)
amount = models.FloatField(default=0.0)
percent_complete = models.FloatField(default=0.0)
# TODO: add validator to make sure the range is 0.0 - 100
start_date = models.DateField(null=True, blank=True, default = None)
end_date = models.DateField(null=True, blank=True, default = None)
class AddressModel(models.Model):
address_1 = models.CharField(max_length=128)
address_2 = models.CharField(max_length=128, blank=True)
city = models.CharField(max_length=64)
state = models.CharField(max_length=2)
zip_code = models.CharField(max_length=5)
class Employee(IdMixin, TimeMixin):
manager = models.ForeignKey("self", on_delete=models.CASCADE, related_name="manager_employee")
user = models.OneToOneField(User, on_delete=models.CASCADE)
primaryAddress = models.ForeignKey(AddressModel, on_delete=models.CASCADE, related_name="primary_address_employee")
workAddress = models.ForeignKey(AddressModel, on_delete=models.CASCADE, related_name="work_address_employee")
phoneNumber = PhoneNumberField(null=False, blank=False, unique=True)
slary= models.FloatField(default=0.0)
# TODO: get hourly salary
# TODO: roles, jpbTitles
class TimeCard(IdMixin, TimeMixin):
startDate = models.DateField(null=True, default = None)
endDate = models.DateField(null=True, default = None)
employee = models.ForeignKey(Employee, on_delete=models.CASCADE, related_name="employee")
approvedBy = models.ForeignKey(Employee, on_delete=models.CASCADE, null=True, related_name="approved_by")
approvedDate = models.DateField(null=True, default=None)
approvalComment = models.TextField(max_length=256, default="")
# TODO: do the is approved comment
class TimeCardCell(IdMixin, TimeMixin):
timeCard = models.ForeignKey(TimeCard, on_delete=models.CASCADE)
date = models.DateField(null=True, default = None)
hour = models.FloatField(default = 0.0)

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,597 @@
/*--------------------------------
hermes-dashboard-icons Web Font - built using nucleoapp.com
License - nucleoapp.com/license/
-------------------------------- */
@font-face {
font-family: 'NucleoIcons';
src: url('../fonts/nucleo-icons.eot');
src: url('../fonts/nucleo-icons.eot') format('embedded-opentype'), url('../fonts/nucleo-icons.woff2') format('woff2'), url('../fonts/nucleo-icons.woff') format('woff'), url('../fonts/nucleo-icons.ttf') format('truetype'), url('../fonts/nucleo-icons.svg') format('svg');
font-weight: normal;
font-style: normal;
}
/*------------------------
base class definition
-------------------------*/
.ni {
display: inline-block;
font: normal normal normal 14px/1 NucleoIcons;
font-size: inherit;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/*------------------------
change icon size
-------------------------*/
.ni-lg {
font-size: 1.33333333em;
line-height: 0.75em;
vertical-align: -15%;
}
.ni-2x {
font-size: 2em;
}
.ni-3x {
font-size: 3em;
}
.ni-4x {
font-size: 4em;
}
.ni-5x {
font-size: 5em;
}
/*----------------------------------
add a square/circle background
-----------------------------------*/
.ni.square,
.ni.circle {
padding: 0.33333333em;
vertical-align: -16%;
background-color: #eee;
}
.ni.circle {
border-radius: 50%;
}
/*------------------------
list icons
-------------------------*/
.ni-ul {
padding-left: 0;
margin-left: 2.14285714em;
list-style-type: none;
}
.ni-ul>li {
position: relative;
}
.ni-ul>li>.ni {
position: absolute;
left: -1.57142857em;
top: 0.14285714em;
text-align: center;
}
.ni-ul>li>.ni.lg {
top: 0;
left: -1.35714286em;
}
.ni-ul>li>.ni.circle,
.ni-ul>li>.ni.square {
top: -0.19047619em;
left: -1.9047619em;
}
/*------------------------
spinning icons
-------------------------*/
.ni.spin {
-webkit-animation: nc-spin 2s infinite linear;
-moz-animation: nc-spin 2s infinite linear;
animation: nc-spin 2s infinite linear;
}
@-webkit-keyframes nc-spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
@-moz-keyframes nc-spin {
0% {
-moz-transform: rotate(0deg);
}
100% {
-moz-transform: rotate(360deg);
}
}
@keyframes nc-spin {
0% {
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-ms-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
-ms-transform: rotate(360deg);
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
}
/*------------------------
rotated/flipped icons
-------------------------*/
.ni.rotate-90 {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-ms-transform: rotate(90deg);
-o-transform: rotate(90deg);
transform: rotate(90deg);
}
.ni.rotate-180 {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
-webkit-transform: rotate(180deg);
-moz-transform: rotate(180deg);
-ms-transform: rotate(180deg);
-o-transform: rotate(180deg);
transform: rotate(180deg);
}
.ni.rotate-270 {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
-webkit-transform: rotate(270deg);
-moz-transform: rotate(270deg);
-ms-transform: rotate(270deg);
-o-transform: rotate(270deg);
transform: rotate(270deg);
}
.ni.flip-y {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0);
-webkit-transform: scale(-1, 1);
-moz-transform: scale(-1, 1);
-ms-transform: scale(-1, 1);
-o-transform: scale(-1, 1);
transform: scale(-1, 1);
}
.ni.flip-x {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
-webkit-transform: scale(1, -1);
-moz-transform: scale(1, -1);
-ms-transform: scale(1, -1);
-o-transform: scale(1, -1);
transform: scale(1, -1);
}
/*------------------------
font icons
-------------------------*/
.ni-active-40::before {
content: "\ea02";
}
.ni-air-baloon::before {
content: "\ea03";
}
.ni-album-2::before {
content: "\ea04";
}
.ni-align-center::before {
content: "\ea05";
}
.ni-align-left-2::before {
content: "\ea06";
}
.ni-ambulance::before {
content: "\ea07";
}
.ni-app::before {
content: "\ea08";
}
.ni-archive-2::before {
content: "\ea09";
}
.ni-atom::before {
content: "\ea0a";
}
.ni-badge::before {
content: "\ea0b";
}
.ni-bag-17::before {
content: "\ea0c";
}
.ni-basket::before {
content: "\ea0d";
}
.ni-bell-55::before {
content: "\ea0e";
}
.ni-bold-down::before {
content: "\ea0f";
}
.ni-bold-left::before {
content: "\ea10";
}
.ni-bold-right::before {
content: "\ea11";
}
.ni-bold-up::before {
content: "\ea12";
}
.ni-bold::before {
content: "\ea13";
}
.ni-book-bookmark::before {
content: "\ea14";
}
.ni-books::before {
content: "\ea15";
}
.ni-box-2::before {
content: "\ea16";
}
.ni-briefcase-24::before {
content: "\ea17";
}
.ni-building::before {
content: "\ea18";
}
.ni-bulb-61::before {
content: "\ea19";
}
.ni-bullet-list-67::before {
content: "\ea1a";
}
.ni-bus-front-12::before {
content: "\ea1b";
}
.ni-button-pause::before {
content: "\ea1c";
}
.ni-button-play::before {
content: "\ea1d";
}
.ni-button-power::before {
content: "\ea1e";
}
.ni-calendar-grid-58::before {
content: "\ea1f";
}
.ni-camera-compact::before {
content: "\ea20";
}
.ni-caps-small::before {
content: "\ea21";
}
.ni-cart::before {
content: "\ea22";
}
.ni-chart-bar-32::before {
content: "\ea23";
}
.ni-chart-pie-35::before {
content: "\ea24";
}
.ni-chat-round::before {
content: "\ea25";
}
.ni-check-bold::before {
content: "\ea26";
}
.ni-circle-08::before {
content: "\ea27";
}
.ni-cloud-download-95::before {
content: "\ea28";
}
.ni-cloud-upload-96::before {
content: "\ea29";
}
.ni-compass-04::before {
content: "\ea2a";
}
.ni-controller::before {
content: "\ea2b";
}
.ni-credit-card::before {
content: "\ea2c";
}
.ni-curved-next::before {
content: "\ea2d";
}
.ni-delivery-fast::before {
content: "\ea2e";
}
.ni-diamond::before {
content: "\ea2f";
}
.ni-email-83::before {
content: "\ea30";
}
.ni-fat-add::before {
content: "\ea31";
}
.ni-fat-delete::before {
content: "\ea32";
}
.ni-fat-remove::before {
content: "\ea33";
}
.ni-favourite-28::before {
content: "\ea34";
}
.ni-folder-17::before {
content: "\ea35";
}
.ni-glasses-2::before {
content: "\ea36";
}
.ni-hat-3::before {
content: "\ea37";
}
.ni-headphones::before {
content: "\ea38";
}
.ni-html5::before {
content: "\ea39";
}
.ni-istanbul::before {
content: "\ea3a";
}
.ni-key-25::before {
content: "\ea3b";
}
.ni-laptop::before {
content: "\ea3c";
}
.ni-like-2::before {
content: "\ea3d";
}
.ni-lock-circle-open::before {
content: "\ea3e";
}
.ni-map-big::before {
content: "\ea3f";
}
.ni-mobile-button::before {
content: "\ea40";
}
.ni-money-coins::before {
content: "\ea41";
}
.ni-note-03::before {
content: "\ea42";
}
.ni-notification-70::before {
content: "\ea43";
}
.ni-palette::before {
content: "\ea44";
}
.ni-paper-diploma::before {
content: "\ea45";
}
.ni-pin-3::before {
content: "\ea46";
}
.ni-planet::before {
content: "\ea47";
}
.ni-ruler-pencil::before {
content: "\ea48";
}
.ni-satisfied::before {
content: "\ea49";
}
.ni-scissors::before {
content: "\ea4a";
}
.ni-send::before {
content: "\ea4b";
}
.ni-settings-gear-65::before {
content: "\ea4c";
}
.ni-settings::before {
content: "\ea4d";
}
.ni-single-02::before {
content: "\ea4e";
}
.ni-single-copy-04::before {
content: "\ea4f";
}
.ni-sound-wave::before {
content: "\ea50";
}
.ni-spaceship::before {
content: "\ea51";
}
.ni-square-pin::before {
content: "\ea52";
}
.ni-support-16::before {
content: "\ea53";
}
.ni-tablet-button::before {
content: "\ea54";
}
.ni-tag::before {
content: "\ea55";
}
.ni-tie-bow::before {
content: "\ea56";
}
.ni-time-alarm::before {
content: "\ea57";
}
.ni-trophy::before {
content: "\ea58";
}
.ni-tv-2::before {
content: "\ea59";
}
.ni-umbrella-13::before {
content: "\ea5a";
}
.ni-user-run::before {
content: "\ea5b";
}
.ni-vector::before {
content: "\ea5c";
}
.ni-watch-time::before {
content: "\ea5d";
}
.ni-world::before {
content: "\ea5e";
}
.ni-zoom-split-in::before {
content: "\ea5f";
}
.ni-collection::before {
content: "\ea60";
}
.ni-image::before {
content: "\ea61";
}
.ni-shop::before {
content: "\ea62";
}
.ni-ungroup::before {
content: "\ea63";
}
.ni-world-2::before {
content: "\ea64";
}
.ni-ui-04::before {
content: "\ea65";
}
/* all icon font classes list here */

View File

@@ -0,0 +1,135 @@
/* Generated using nucleoapp.com */
/* --------------------------------
Icon colors
-------------------------------- */
.icon {
display: inline-block;
/* icon primary color */
color: #111111;
height: 1em;
width: 1em;
}
.icon use {
/* icon secondary color - fill */
fill: #7ea6f6;
}
.icon.icon-outline use {
/* icon secondary color - stroke */
stroke: #7ea6f6;
}
/* --------------------------------
Change icon size
-------------------------------- */
.icon-xs {
height: 0.5em;
width: 0.5em;
}
.icon-sm {
height: 0.8em;
width: 0.8em;
}
.icon-lg {
height: 1.6em;
width: 1.6em;
}
.icon-xl {
height: 2em;
width: 2em;
}
/* --------------------------------
Align icon and text
-------------------------------- */
.icon-text-aligner {
/* add this class to parent element that contains icon + text */
display: flex;
align-items: center;
}
.icon-text-aligner .icon {
color: inherit;
margin-right: 0.4em;
}
.icon-text-aligner .icon use {
color: inherit;
fill: currentColor;
}
.icon-text-aligner .icon.icon-outline use {
stroke: currentColor;
}
/* --------------------------------
Icon reset values - used to enable color customizations
-------------------------------- */
.icon {
fill: currentColor;
stroke: none;
}
.icon.icon-outline {
fill: none;
stroke: currentColor;
}
.icon use {
stroke: none;
}
.icon.icon-outline use {
fill: none;
}
/* --------------------------------
Stroke effects - Nucleo outline icons
- 16px icons -> up to 1px stroke (16px outline icons do not support stroke changes)
- 24px, 32px icons -> up to 2px stroke
- 48px, 64px icons -> up to 4px stroke
-------------------------------- */
.icon-outline.icon-stroke-1 {
stroke-width: 1px;
}
.icon-outline.icon-stroke-2 {
stroke-width: 2px;
}
.icon-outline.icon-stroke-3 {
stroke-width: 3px;
}
.icon-outline.icon-stroke-4 {
stroke-width: 4px;
}
.icon-outline.icon-stroke-1 use,
.icon-outline.icon-stroke-3 use {
-webkit-transform: translateX(0.5px) translateY(0.5px);
-moz-transform: translateX(0.5px) translateY(0.5px);
-ms-transform: translateX(0.5px) translateY(0.5px);
-o-transform: translateX(0.5px) translateY(0.5px);
transform: translateX(0.5px) translateY(0.5px);
}

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

@@ -0,0 +1,876 @@
// =========================================================
// Material Dashboard 2 - v3.1.0
// =========================================================
// Product Page: https://www.creative-tim.com/product/material-dashboard
// Copyright 2023 Creative Tim (https://www.creative-tim.com)
// Licensed under MIT (https://github.com/creativetimofficial/material-dashboard/blob/master/LICENSE.md)
// Coded by www.creative-tim.com
// =========================================================
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
"use strict";
(function() {
var isWindows = navigator.platform.indexOf('Win') > -1 ? true : false;
if (isWindows) {
// if we are on windows OS we activate the perfectScrollbar function
if (document.getElementsByClassName('main-content')[0]) {
var mainpanel = document.querySelector('.main-content');
var ps = new PerfectScrollbar(mainpanel);
};
if (document.getElementsByClassName('sidenav')[0]) {
var sidebar = document.querySelector('.sidenav');
var ps1 = new PerfectScrollbar(sidebar);
};
if (document.getElementsByClassName('navbar-collapse')[0]) {
var fixedplugin = document.querySelector('.navbar:not(.navbar-expand-lg) .navbar-collapse');
var ps2 = new PerfectScrollbar(fixedplugin);
};
if (document.getElementsByClassName('fixed-plugin')[0]) {
var fixedplugin = document.querySelector('.fixed-plugin');
var ps3 = new PerfectScrollbar(fixedplugin);
};
};
})();
// Verify navbar blur on scroll
if (document.getElementById('navbarBlur')) {
navbarBlurOnScroll('navbarBlur');
}
// initialization of Tooltips
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function(tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl)
})
// when input is focused add focused class for style
function focused(el) {
if (el.parentElement.classList.contains('input-group')) {
el.parentElement.classList.add('focused');
}
}
// when input is focused remove focused class for style
function defocused(el) {
if (el.parentElement.classList.contains('input-group')) {
el.parentElement.classList.remove('focused');
}
}
// helper for adding on all elements multiple attributes
function setAttributes(el, options) {
Object.keys(options).forEach(function(attr) {
el.setAttribute(attr, options[attr]);
})
}
// adding on inputs attributes for calling the focused and defocused functions
if (document.querySelectorAll('.input-group').length != 0) {
var allInputs = document.querySelectorAll('input.form-control');
allInputs.forEach(el => setAttributes(el, {
"onfocus": "focused(this)",
"onfocusout": "defocused(this)"
}));
}
// Fixed Plugin
if (document.querySelector('.fixed-plugin')) {
var fixedPlugin = document.querySelector('.fixed-plugin');
var fixedPlugin = document.querySelector('.fixed-plugin');
var fixedPluginButton = document.querySelector('.fixed-plugin-button');
var fixedPluginButtonNav = document.querySelector('.fixed-plugin-button-nav');
var fixedPluginCard = document.querySelector('.fixed-plugin .card');
var fixedPluginCloseButton = document.querySelectorAll('.fixed-plugin-close-button');
var navbar = document.getElementById('navbarBlur');
var buttonNavbarFixed = document.getElementById('navbarFixed');
if (fixedPluginButton) {
fixedPluginButton.onclick = function() {
if (!fixedPlugin.classList.contains('show')) {
fixedPlugin.classList.add('show');
} else {
fixedPlugin.classList.remove('show');
}
}
}
if (fixedPluginButtonNav) {
fixedPluginButtonNav.onclick = function() {
if (!fixedPlugin.classList.contains('show')) {
fixedPlugin.classList.add('show');
} else {
fixedPlugin.classList.remove('show');
}
}
}
fixedPluginCloseButton.forEach(function(el) {
el.onclick = function() {
fixedPlugin.classList.remove('show');
}
})
document.querySelector('body').onclick = function(e) {
if (e.target != fixedPluginButton && e.target != fixedPluginButtonNav && e.target.closest('.fixed-plugin .card') != fixedPluginCard) {
fixedPlugin.classList.remove('show');
}
}
if (navbar) {
if (navbar.getAttribute('data-scroll') == 'true' && buttonNavbarFixed) {
buttonNavbarFixed.setAttribute("checked", "true");
}
}
}
//Set Sidebar Color
function sidebarColor(a) {
var parent = document.querySelector(".nav-link.active");
var color = a.getAttribute("data-color");
if (parent.classList.contains('bg-gradient-primary')) {
parent.classList.remove('bg-gradient-primary');
}
if (parent.classList.contains('bg-gradient-dark')) {
parent.classList.remove('bg-gradient-dark');
}
if (parent.classList.contains('bg-gradient-info')) {
parent.classList.remove('bg-gradient-info');
}
if (parent.classList.contains('bg-gradient-success')) {
parent.classList.remove('bg-gradient-success');
}
if (parent.classList.contains('bg-gradient-warning')) {
parent.classList.remove('bg-gradient-warning');
}
if (parent.classList.contains('bg-gradient-danger')) {
parent.classList.remove('bg-gradient-danger');
}
parent.classList.add('bg-gradient-' + color);
}
// Set Sidebar Type
function sidebarType(a) {
var parent = a.parentElement.children;
var color = a.getAttribute("data-class");
var body = document.querySelector("body");
var bodyWhite = document.querySelector("body:not(.dark-version)");
var bodyDark = body.classList.contains('dark-version');
var colors = [];
for (var i = 0; i < parent.length; i++) {
parent[i].classList.remove('active');
colors.push(parent[i].getAttribute('data-class'));
}
if (!a.classList.contains('active')) {
a.classList.add('active');
} else {
a.classList.remove('active');
}
var sidebar = document.querySelector('.sidenav');
for (var i = 0; i < colors.length; i++) {
sidebar.classList.remove(colors[i]);
}
sidebar.classList.add(color);
// Remove text-white/text-dark classes
if (color == 'bg-transparent' || color == 'bg-white') {
var textWhites = document.querySelectorAll('.sidenav .text-white');
for (let i = 0; i < textWhites.length; i++) {
textWhites[i].classList.remove('text-white');
textWhites[i].classList.add('text-dark');
}
} else {
var textDarks = document.querySelectorAll('.sidenav .text-dark');
for (let i = 0; i < textDarks.length; i++) {
textDarks[i].classList.add('text-white');
textDarks[i].classList.remove('text-dark');
}
}
if (color == 'bg-transparent' && bodyDark) {
var textDarks = document.querySelectorAll('.navbar-brand .text-dark');
for (let i = 0; i < textDarks.length; i++) {
textDarks[i].classList.add('text-white');
textDarks[i].classList.remove('text-dark');
}
}
// Remove logo-white/logo-dark
if ((color == 'bg-transparent' || color == 'bg-white') && bodyWhite) {
var navbarBrand = document.querySelector('.navbar-brand-img');
var navbarBrandImg = navbarBrand.src;
if (navbarBrandImg.includes('logo-ct.png')) {
var navbarBrandImgNew = navbarBrandImg.replace("logo-ct", "logo-ct-dark");
navbarBrand.src = navbarBrandImgNew;
}
} else {
var navbarBrand = document.querySelector('.navbar-brand-img');
var navbarBrandImg = navbarBrand.src;
if (navbarBrandImg.includes('logo-ct-dark.png')) {
var navbarBrandImgNew = navbarBrandImg.replace("logo-ct-dark", "logo-ct");
navbarBrand.src = navbarBrandImgNew;
}
}
if (color == 'bg-white' && bodyDark) {
var navbarBrand = document.querySelector('.navbar-brand-img');
var navbarBrandImg = navbarBrand.src;
if (navbarBrandImg.includes('logo-ct.png')) {
var navbarBrandImgNew = navbarBrandImg.replace("logo-ct", "logo-ct-dark");
navbarBrand.src = navbarBrandImgNew;
}
}
}
// Set Navbar Fixed
function navbarFixed(el) {
let classes = ['position-sticky', 'blur', 'shadow-blur', 'mt-4', 'left-auto', 'top-1', 'z-index-sticky'];
const navbar = document.getElementById('navbarBlur');
if (!el.getAttribute("checked")) {
navbar.classList.add(...classes);
navbar.setAttribute('navbar-scroll', 'true');
navbarBlurOnScroll('navbarBlur');
el.setAttribute("checked", "true");
} else {
navbar.classList.remove(...classes);
navbar.setAttribute('navbar-scroll', 'false');
navbarBlurOnScroll('navbarBlur');
el.removeAttribute("checked");
}
};
// Set Navbar Minimized
function navbarMinimize(el) {
var sidenavShow = document.getElementsByClassName('g-sidenav-show')[0];
if (!el.getAttribute("checked")) {
sidenavShow.classList.remove('g-sidenav-pinned');
sidenavShow.classList.add('g-sidenav-hidden');
el.setAttribute("checked", "true");
} else {
sidenavShow.classList.remove('g-sidenav-hidden');
sidenavShow.classList.add('g-sidenav-pinned');
el.removeAttribute("checked");
}
}
// Navbar blur on scroll
function navbarBlurOnScroll(id) {
const navbar = document.getElementById(id);
let navbarScrollActive = navbar ? navbar.getAttribute("data-scroll") : false;
let scrollDistance = 5;
let classes = ['blur', 'shadow-blur', 'left-auto'];
let toggleClasses = ['shadow-none'];
if (navbarScrollActive == 'true') {
window.onscroll = debounce(function() {
if (window.scrollY > scrollDistance) {
blurNavbar();
} else {
transparentNavbar();
}
}, 10);
} else {
window.onscroll = debounce(function() {
transparentNavbar();
}, 10);
}
var isWindows = navigator.platform.indexOf('Win') > -1 ? true : false;
if (isWindows) {
var content = document.querySelector('.main-content');
if (navbarScrollActive == 'true') {
content.addEventListener('ps-scroll-y', debounce(function() {
if (content.scrollTop > scrollDistance) {
blurNavbar();
} else {
transparentNavbar();
}
}, 10));
} else {
content.addEventListener('ps-scroll-y', debounce(function() {
transparentNavbar();
}, 10));
}
}
function blurNavbar() {
navbar.classList.add(...classes)
navbar.classList.remove(...toggleClasses)
toggleNavLinksColor('blur');
}
function transparentNavbar() {
navbar.classList.remove(...classes)
navbar.classList.add(...toggleClasses)
toggleNavLinksColor('transparent');
}
function toggleNavLinksColor(type) {
let navLinks = document.querySelectorAll('.navbar-main .nav-link')
let navLinksToggler = document.querySelectorAll('.navbar-main .sidenav-toggler-line')
if (type === "blur") {
navLinks.forEach(element => {
element.classList.remove('text-body')
});
navLinksToggler.forEach(element => {
element.classList.add('bg-dark')
});
} else if (type === "transparent") {
navLinks.forEach(element => {
element.classList.add('text-body')
});
navLinksToggler.forEach(element => {
element.classList.remove('bg-dark')
});
}
}
}
// Debounce Function
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this,
args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
// initialization of Toasts
document.addEventListener("DOMContentLoaded", function() {
var toastElList = [].slice.call(document.querySelectorAll(".toast"));
var toastList = toastElList.map(function(toastEl) {
return new bootstrap.Toast(toastEl);
});
var toastButtonList = [].slice.call(document.querySelectorAll(".toast-btn"));
toastButtonList.map(function(toastButtonEl) {
toastButtonEl.addEventListener("click", function() {
var toastToTrigger = document.getElementById(toastButtonEl.dataset.target);
if (toastToTrigger) {
var toast = bootstrap.Toast.getInstance(toastToTrigger);
toast.show();
}
});
});
});
// Tabs navigation
var total = document.querySelectorAll('.nav-pills');
function initNavs() {
total.forEach(function(item, i) {
var moving_div = document.createElement('div');
var first_li = item.querySelector('li:first-child .nav-link');
var tab = first_li.cloneNode();
tab.innerHTML = "-";
moving_div.classList.add('moving-tab', 'position-absolute', 'nav-link');
moving_div.appendChild(tab);
item.appendChild(moving_div);
var list_length = item.getElementsByTagName("li").length;
moving_div.style.padding = '0px';
moving_div.style.width = item.querySelector('li:nth-child(1)').offsetWidth + 'px';
moving_div.style.transform = 'translate3d(0px, 0px, 0px)';
moving_div.style.transition = '.5s ease';
item.onmouseover = function(event) {
let target = getEventTarget(event);
let li = target.closest('li'); // get reference
if (li) {
let nodes = Array.from(li.closest('ul').children); // get array
let index = nodes.indexOf(li) + 1;
item.querySelector('li:nth-child(' + index + ') .nav-link').onclick = function() {
moving_div = item.querySelector('.moving-tab');
let sum = 0;
if (item.classList.contains('flex-column')) {
for (var j = 1; j <= nodes.indexOf(li); j++) {
sum += item.querySelector('li:nth-child(' + j + ')').offsetHeight;
}
moving_div.style.transform = 'translate3d(0px,' + sum + 'px, 0px)';
moving_div.style.height = item.querySelector('li:nth-child(' + j + ')').offsetHeight;
} else {
for (var j = 1; j <= nodes.indexOf(li); j++) {
sum += item.querySelector('li:nth-child(' + j + ')').offsetWidth;
}
moving_div.style.transform = 'translate3d(' + sum + 'px, 0px, 0px)';
moving_div.style.width = item.querySelector('li:nth-child(' + index + ')').offsetWidth + 'px';
}
}
}
}
});
}
setTimeout(function() {
initNavs();
}, 100);
// Tabs navigation resize
window.addEventListener('resize', function(event) {
total.forEach(function(item, i) {
item.querySelector('.moving-tab').remove();
var moving_div = document.createElement('div');
var tab = item.querySelector(".nav-link.active").cloneNode();
tab.innerHTML = "-";
moving_div.classList.add('moving-tab', 'position-absolute', 'nav-link');
moving_div.appendChild(tab);
item.appendChild(moving_div);
moving_div.style.padding = '0px';
moving_div.style.transition = '.5s ease';
let li = item.querySelector(".nav-link.active").parentElement;
if (li) {
let nodes = Array.from(li.closest('ul').children); // get array
let index = nodes.indexOf(li) + 1;
let sum = 0;
if (item.classList.contains('flex-column')) {
for (var j = 1; j <= nodes.indexOf(li); j++) {
sum += item.querySelector('li:nth-child(' + j + ')').offsetHeight;
}
moving_div.style.transform = 'translate3d(0px,' + sum + 'px, 0px)';
moving_div.style.width = item.querySelector('li:nth-child(' + index + ')').offsetWidth + 'px';
moving_div.style.height = item.querySelector('li:nth-child(' + j + ')').offsetHeight;
} else {
for (var j = 1; j <= nodes.indexOf(li); j++) {
sum += item.querySelector('li:nth-child(' + j + ')').offsetWidth;
}
moving_div.style.transform = 'translate3d(' + sum + 'px, 0px, 0px)';
moving_div.style.width = item.querySelector('li:nth-child(' + index + ')').offsetWidth + 'px';
}
}
});
if (window.innerWidth < 991) {
total.forEach(function(item, i) {
if (!item.classList.contains('flex-column')) {
item.classList.remove('flex-row');
item.classList.add('flex-column', 'on-resize');
let li = item.querySelector(".nav-link.active").parentElement;
let nodes = Array.from(li.closest('ul').children); // get array
let index = nodes.indexOf(li) + 1;
let sum = 0;
for (var j = 1; j <= nodes.indexOf(li); j++) {
sum += item.querySelector('li:nth-child(' + j + ')').offsetHeight;
}
var moving_div = document.querySelector('.moving-tab');
moving_div.style.width = item.querySelector('li:nth-child(1)').offsetWidth + 'px';
moving_div.style.transform = 'translate3d(0px,' + sum + 'px, 0px)';
}
});
} else {
total.forEach(function(item, i) {
if (item.classList.contains('on-resize')) {
item.classList.remove('flex-column', 'on-resize');
item.classList.add('flex-row');
let li = item.querySelector(".nav-link.active").parentElement;
let nodes = Array.from(li.closest('ul').children); // get array
let index = nodes.indexOf(li) + 1;
let sum = 0;
for (var j = 1; j <= nodes.indexOf(li); j++) {
sum += item.querySelector('li:nth-child(' + j + ')').offsetWidth;
}
var moving_div = document.querySelector('.moving-tab');
moving_div.style.transform = 'translate3d(' + sum + 'px, 0px, 0px)';
moving_div.style.width = item.querySelector('li:nth-child(' + index + ')').offsetWidth + 'px';
}
})
}
});
// Function to remove flex row on mobile devices
if (window.innerWidth < 991) {
total.forEach(function(item, i) {
if (item.classList.contains('flex-row')) {
item.classList.remove('flex-row');
item.classList.add('flex-column', 'on-resize');
}
});
}
function getEventTarget(e) {
e = e || window.event;
return e.target || e.srcElement;
}
// End tabs navigation
window.onload = function() {
// Material Design Input function
var inputs = document.querySelectorAll('input');
for (var i = 0; i < inputs.length; i++) {
inputs[i].addEventListener('focus', function(e) {
this.parentElement.classList.add('is-focused');
}, false);
inputs[i].onkeyup = function(e) {
if (this.value != "") {
this.parentElement.classList.add('is-filled');
} else {
this.parentElement.classList.remove('is-filled');
}
};
inputs[i].addEventListener('focusout', function(e) {
if (this.value != "") {
this.parentElement.classList.add('is-filled');
}
this.parentElement.classList.remove('is-focused');
}, false);
}
// Ripple Effect
var ripples = document.querySelectorAll('.btn');
for (var i = 0; i < ripples.length; i++) {
ripples[i].addEventListener('click', function(e) {
var targetEl = e.target;
var rippleDiv = targetEl.querySelector('.ripple');
rippleDiv = document.createElement('span');
rippleDiv.classList.add('ripple');
rippleDiv.style.width = rippleDiv.style.height = Math.max(targetEl.offsetWidth, targetEl.offsetHeight) + 'px';
targetEl.appendChild(rippleDiv);
rippleDiv.style.left = (e.offsetX - rippleDiv.offsetWidth / 2) + 'px';
rippleDiv.style.top = (e.offsetY - rippleDiv.offsetHeight / 2) + 'px';
rippleDiv.classList.add('ripple');
setTimeout(function() {
rippleDiv.parentElement.removeChild(rippleDiv);
}, 600);
}, false);
}
};
// Toggle Sidenav
const iconNavbarSidenav = document.getElementById('iconNavbarSidenav');
const iconSidenav = document.getElementById('iconSidenav');
const sidenav = document.getElementById('sidenav-main');
let body = document.getElementsByTagName('body')[0];
let className = 'g-sidenav-pinned';
if (iconNavbarSidenav) {
iconNavbarSidenav.addEventListener("click", toggleSidenav);
}
if (iconSidenav) {
iconSidenav.addEventListener("click", toggleSidenav);
}
function toggleSidenav() {
if (body.classList.contains(className)) {
body.classList.remove(className);
setTimeout(function() {
sidenav.classList.remove('bg-white');
}, 100);
sidenav.classList.remove('bg-transparent');
} else {
body.classList.add(className);
sidenav.classList.add('bg-white');
sidenav.classList.remove('bg-transparent');
iconSidenav.classList.remove('d-none');
}
}
// Resize navbar color depends on configurator active type of sidenav
let referenceButtons = document.querySelector('[data-class]');
if (sidenav) {
window.addEventListener("resize", navbarColorOnResize);
function navbarColorOnResize() {
if (window.innerWidth > 1200) {
if (referenceButtons?.classList.contains('active') && referenceButtons?.getAttribute('data-class') === 'bg-transparent') {
sidenav.classList.remove('bg-white');
} else {
sidenav.classList.add('bg-white');
}
} else {
sidenav.classList.add('bg-white');
sidenav.classList.remove('bg-transparent');
}
}
}
// Deactivate sidenav type buttons on resize and small screens
window.addEventListener("resize", sidenavTypeOnResize);
window.addEventListener("load", sidenavTypeOnResize);
function sidenavTypeOnResize() {
let elements = document.querySelectorAll('[onclick="sidebarType(this)"]');
if (window.innerWidth < 1200) {
elements.forEach(function(el) {
el.classList.add('disabled');
});
} else {
elements.forEach(function(el) {
el.classList.remove('disabled');
});
}
}
// Light Mode / Dark Mode
function darkMode(el) {
const body = document.getElementsByTagName('body')[0];
const hr = document.querySelectorAll('div:not(.sidenav) > hr');
const hr_card = document.querySelectorAll('div:not(.bg-gradient-dark) hr');
const text_btn = document.querySelectorAll('button:not(.btn) > .text-dark');
const text_span = document.querySelectorAll('span.text-dark, .breadcrumb .text-dark');
const text_span_white = document.querySelectorAll('span.text-white, .breadcrumb .text-white');
const text_strong = document.querySelectorAll('strong.text-dark');
const text_strong_white = document.querySelectorAll('strong.text-white');
const text_nav_link = document.querySelectorAll('a.nav-link.text-dark');
const text_nav_link_white = document.querySelectorAll('a.nav-link.text-white');
const secondary = document.querySelectorAll('.text-secondary');
const bg_gray_100 = document.querySelectorAll('.bg-gray-100');
const bg_gray_600 = document.querySelectorAll('.bg-gray-600');
const btn_text_dark = document.querySelectorAll('.btn.btn-link.text-dark, .material-icons.text-dark');
const btn_text_white = document.querySelectorAll('.btn.btn-link.text-white, .material-icons.text-white');
const card_border = document.querySelectorAll('.card.border');
const card_border_dark = document.querySelectorAll('.card.border.border-dark');
const svg = document.querySelectorAll('g');
if (!el.getAttribute("checked")) {
body.classList.add('dark-version');
for (var i = 0; i < hr.length; i++) {
if (hr[i].classList.contains('dark')) {
hr[i].classList.remove('dark');
hr[i].classList.add('light');
}
}
for (var i = 0; i < hr_card.length; i++) {
if (hr_card[i].classList.contains('dark')) {
hr_card[i].classList.remove('dark');
hr_card[i].classList.add('light');
}
}
for (var i = 0; i < text_btn.length; i++) {
if (text_btn[i].classList.contains('text-dark')) {
text_btn[i].classList.remove('text-dark');
text_btn[i].classList.add('text-white');
}
}
for (var i = 0; i < text_span.length; i++) {
if (text_span[i].classList.contains('text-dark')) {
text_span[i].classList.remove('text-dark');
text_span[i].classList.add('text-white');
}
}
for (var i = 0; i < text_strong.length; i++) {
if (text_strong[i].classList.contains('text-dark')) {
text_strong[i].classList.remove('text-dark');
text_strong[i].classList.add('text-white');
}
}
for (var i = 0; i < text_nav_link.length; i++) {
if (text_nav_link[i].classList.contains('text-dark')) {
text_nav_link[i].classList.remove('text-dark');
text_nav_link[i].classList.add('text-white');
}
}
for (var i = 0; i < secondary.length; i++) {
if (secondary[i].classList.contains('text-secondary')) {
secondary[i].classList.remove('text-secondary');
secondary[i].classList.add('text-white');
secondary[i].classList.add('opacity-8');
}
}
for (var i = 0; i < bg_gray_100.length; i++) {
if (bg_gray_100[i].classList.contains('bg-gray-100')) {
bg_gray_100[i].classList.remove('bg-gray-100');
bg_gray_100[i].classList.add('bg-gray-600');
}
}
for (var i = 0; i < btn_text_dark.length; i++) {
btn_text_dark[i].classList.remove('text-dark');
btn_text_dark[i].classList.add('text-white');
}
for (var i = 0; i < svg.length; i++) {
if (svg[i].hasAttribute('fill')) {
svg[i].setAttribute('fill', '#fff');
}
}
for (var i = 0; i < card_border.length; i++) {
card_border[i].classList.add('border-dark');
}
el.setAttribute("checked", "true");
} else {
body.classList.remove('dark-version');
for (var i = 0; i < hr.length; i++) {
if (hr[i].classList.contains('light')) {
hr[i].classList.add('dark');
hr[i].classList.remove('light');
}
}
for (var i = 0; i < hr_card.length; i++) {
if (hr_card[i].classList.contains('light')) {
hr_card[i].classList.add('dark');
hr_card[i].classList.remove('light');
}
}
for (var i = 0; i < text_btn.length; i++) {
if (text_btn[i].classList.contains('text-white')) {
text_btn[i].classList.remove('text-white');
text_btn[i].classList.add('text-dark');
}
}
for (var i = 0; i < text_span_white.length; i++) {
if (text_span_white[i].classList.contains('text-white') && !text_span_white[i].closest('.sidenav') && !text_span_white[i].closest('.card.bg-gradient-dark')) {
text_span_white[i].classList.remove('text-white');
text_span_white[i].classList.add('text-dark');
}
}
for (var i = 0; i < text_strong_white.length; i++) {
if (text_strong_white[i].classList.contains('text-white')) {
text_strong_white[i].classList.remove('text-white');
text_strong_white[i].classList.add('text-dark');
}
}
for (var i = 0; i < text_nav_link_white.length; i++) {
if (text_nav_link_white[i].classList.contains('text-white') && !text_nav_link_white[i].closest('.sidenav')) {
text_nav_link_white[i].classList.remove('text-white');
text_nav_link_white[i].classList.add('text-dark');
}
}
for (var i = 0; i < secondary.length; i++) {
if (secondary[i].classList.contains('text-white')) {
secondary[i].classList.remove('text-white');
secondary[i].classList.remove('opacity-8');
secondary[i].classList.add('text-dark');
}
}
for (var i = 0; i < bg_gray_600.length; i++) {
if (bg_gray_600[i].classList.contains('bg-gray-600')) {
bg_gray_600[i].classList.remove('bg-gray-600');
bg_gray_600[i].classList.add('bg-gray-100');
}
}
for (var i = 0; i < svg.length; i++) {
if (svg[i].hasAttribute('fill')) {
svg[i].setAttribute('fill', '#252f40');
}
}
for (var i = 0; i < btn_text_white.length; i++) {
if (!btn_text_white[i].closest('.card.bg-gradient-dark')) {
btn_text_white[i].classList.remove('text-white');
btn_text_white[i].classList.add('text-dark');
}
}
for (var i = 0; i < card_border_dark.length; i++) {
card_border_dark[i].classList.remove('border-dark');
}
el.removeAttribute("checked");
}
};
// side bullets
const indicators = document.querySelectorAll(".indicator");
const sections = document.querySelectorAll("section");
if (indicators) {
const resetCurrentActiveIndicator = () => {
const activeIndicator = document.querySelector(".indicator.active");
if (activeIndicator) {
activeIndicator.classList.remove("active");
}
};
const onSectionLeavesViewport = (section) => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
resetCurrentActiveIndicator();
const element = entry.target;
const indicator = document.querySelector(`a[href='#${element.id}']`);
indicator.classList.add("active");
return;
}
});
}, {
root: null,
rootMargin: "0px",
threshold: 0.75
}
);
observer.observe(section);
};
indicators.forEach((indicator) => {
indicator.addEventListener("click", function(event) {
event.preventDefault();
document
.querySelector(this.getAttribute("href"))
.scrollIntoView({
behavior: "smooth"
});
resetCurrentActiveIndicator();
this.classList.add("active");
});
});
sections.forEach(onSectionLeavesViewport);
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,130 @@
//
// Chart extension for making the bars rounded
// Code from: https://codepen.io/jedtrow/full/ygRYgo
//
Chart.elements.Rectangle.prototype.draw = function() {
var ctx = this._chart.ctx;
var vm = this._view;
var left, right, top, bottom, signX, signY, borderSkipped, radius;
var borderWidth = vm.borderWidth;
// Set Radius Here
// If radius is large enough to cause drawing errors a max radius is imposed
var cornerRadius = 6;
if (!vm.horizontal) {
// bar
left = vm.x - vm.width / 2;
right = vm.x + vm.width / 2;
top = vm.y;
bottom = vm.base;
signX = 1;
signY = bottom > top ? 1 : -1;
borderSkipped = vm.borderSkipped || 'bottom';
} else {
// horizontal bar
left = vm.base;
right = vm.x;
top = vm.y - vm.height / 2;
bottom = vm.y + vm.height / 2;
signX = right > left ? 1 : -1;
signY = 1;
borderSkipped = vm.borderSkipped || 'left';
}
// Canvas doesn't allow us to stroke inside the width so we can
// adjust the sizes to fit if we're setting a stroke on the line
if (borderWidth) {
// borderWidth shold be less than bar width and bar height.
var barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
borderWidth = borderWidth > barSize ? barSize : borderWidth;
var halfStroke = borderWidth / 2;
// Adjust borderWidth when bar top position is near vm.base(zero).
var borderLeft = left + (borderSkipped !== 'left' ? halfStroke * signX : 0);
var borderRight = right + (borderSkipped !== 'right' ? -halfStroke * signX : 0);
var borderTop = top + (borderSkipped !== 'top' ? halfStroke * signY : 0);
var borderBottom = bottom + (borderSkipped !== 'bottom' ? -halfStroke * signY : 0);
// not become a vertical line?
if (borderLeft !== borderRight) {
top = borderTop;
bottom = borderBottom;
}
// not become a horizontal line?
if (borderTop !== borderBottom) {
left = borderLeft;
right = borderRight;
}
}
ctx.beginPath();
ctx.fillStyle = vm.backgroundColor;
ctx.strokeStyle = vm.borderColor;
ctx.lineWidth = borderWidth;
// Corner points, from bottom-left to bottom-right clockwise
// | 1 2 |
// | 0 3 |
var corners = [
[left, bottom],
[left, top],
[right, top],
[right, bottom]
];
// Find first (starting) corner with fallback to 'bottom'
var borders = ['bottom', 'left', 'top', 'right'];
var startCorner = borders.indexOf(borderSkipped, 0);
if (startCorner === -1) {
startCorner = 0;
}
function cornerAt(index) {
return corners[(startCorner + index) % 4];
}
// Draw rectangle from 'startCorner'
var corner = cornerAt(0);
ctx.moveTo(corner[0], corner[1]);
for (var i = 1; i < 4; i++) {
corner = cornerAt(i);
nextCornerId = i + 1;
if (nextCornerId == 4) {
nextCornerId = 0
}
nextCorner = cornerAt(nextCornerId);
width = corners[2][0] - corners[1][0];
height = corners[0][1] - corners[1][1];
x = corners[1][0];
y = corners[1][1];
var radius = cornerRadius;
// Fix radius being too large
if (radius > height / 2) {
radius = height / 2;
}
if (radius > width / 2) {
radius = width / 2;
}
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
}
ctx.fill();
if (borderWidth) {
ctx.stroke();
}
};

View File

@@ -0,0 +1,432 @@
/*
Creative Tim Modifications
Lines: 238, 239 was changed from top: 5px to top: 50% and we added margin-top: -13px. In this way the close button will be aligned vertically
Line:222 - modified when the icon is set, we add the class "alert-with-icon", so there will be enough space for the icon.
*/
/*
* Project: Bootstrap Notify = v3.1.5
* Description: Turns standard Bootstrap alerts into "Growl-like" notifications.
* Author: Mouse0270 aka Robert McIntosh
* License: MIT License
* Website: https://github.com/mouse0270/bootstrap-growl
*/
/* global define:false, require: false, jQuery:false */
(function(factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS
factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function($) {
// Create the defaults once
var defaults = {
element: 'body',
position: null,
type: "info",
allow_dismiss: true,
allow_duplicates: true,
newest_on_top: false,
showProgressbar: false,
placement: {
from: "top",
align: "right"
},
offset: 20,
spacing: 10,
z_index: 1060,
delay: 5000,
timer: 1000,
url_target: '_blank',
mouse_over: null,
animate: {
enter: 'animated fadeInDown',
exit: 'animated fadeOutUp'
},
onShow: null,
onShown: null,
onClose: null,
onClosed: null,
onClick: null,
icon_type: 'class',
template: '<div data-notify="container" class="col-xs-11 col-sm-4 alert alert-{0}" role="alert"><button type="button" aria-hidden="true" class="close" data-notify="dismiss"><i class="tim-icons icon-simple-remove"></i></button><span data-notify="icon"></span> <span data-notify="title">{1}</span> <span data-notify="message">{2}</span><div class="progress" data-notify="progressbar"><div class="progress-bar progress-bar-{0}" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;"></div></div><a href="{3}" target="{4}" data-notify="url"></a></div>'
};
String.format = function() {
var args = arguments;
var str = arguments[0];
return str.replace(/(\{\{\d\}\}|\{\d\})/g, function(str) {
if (str.substring(0, 2) === "{{") return str;
var num = parseInt(str.match(/\d/)[0]);
return args[num + 1];
});
};
function isDuplicateNotification(notification) {
var isDupe = false;
$('[data-notify="container"]').each(function(i, el) {
var $el = $(el);
var title = $el.find('[data-notify="title"]').html().trim();
var message = $el.find('[data-notify="message"]').html().trim();
// The input string might be different than the actual parsed HTML string!
// (<br> vs <br /> for example)
// So we have to force-parse this as HTML here!
var isSameTitle = title === $("<div>" + notification.settings.content.title + "</div>").html().trim();
var isSameMsg = message === $("<div>" + notification.settings.content.message + "</div>").html().trim();
var isSameType = $el.hasClass('alert-' + notification.settings.type);
if (isSameTitle && isSameMsg && isSameType) {
//we found the dupe. Set the var and stop checking.
isDupe = true;
}
return !isDupe;
});
return isDupe;
}
function Notify(element, content, options) {
// Setup Content of Notify
var contentObj = {
content: {
message: typeof content === 'object' ? content.message : content,
title: content.title ? content.title : '',
icon: content.icon ? content.icon : '',
url: content.url ? content.url : '#',
target: content.target ? content.target : '-'
}
};
options = $.extend(true, {}, contentObj, options);
this.settings = $.extend(true, {}, defaults, options);
this._defaults = defaults;
if (this.settings.content.target === "-") {
this.settings.content.target = this.settings.url_target;
}
this.animations = {
start: 'webkitAnimationStart oanimationstart MSAnimationStart animationstart',
end: 'webkitAnimationEnd oanimationend MSAnimationEnd animationend'
};
if (typeof this.settings.offset === 'number') {
this.settings.offset = {
x: this.settings.offset,
y: this.settings.offset
};
}
//if duplicate messages are not allowed, then only continue if this new message is not a duplicate of one that it already showing
if (this.settings.allow_duplicates || (!this.settings.allow_duplicates && !isDuplicateNotification(this))) {
this.init();
}
}
$.extend(Notify.prototype, {
init: function() {
var self = this;
this.buildNotify();
if (this.settings.content.icon) {
this.setIcon();
}
if (this.settings.content.url != "#") {
this.styleURL();
}
this.styleDismiss();
this.placement();
this.bind();
this.notify = {
$ele: this.$ele,
update: function(command, update) {
var commands = {};
if (typeof command === "string") {
commands[command] = update;
} else {
commands = command;
}
for (var cmd in commands) {
switch (cmd) {
case "type":
this.$ele.removeClass('alert-' + self.settings.type);
this.$ele.find('[data-notify="progressbar"] > .progress-bar').removeClass('progress-bar-' + self.settings.type);
self.settings.type = commands[cmd];
this.$ele.addClass('alert-' + commands[cmd]).find('[data-notify="progressbar"] > .progress-bar').addClass('progress-bar-' + commands[cmd]);
break;
case "icon":
var $icon = this.$ele.find('[data-notify="icon"]');
if (self.settings.icon_type.toLowerCase() === 'class') {
$icon.removeClass(self.settings.content.icon).addClass(commands[cmd]);
} else {
if (!$icon.is('img')) {
$icon.find('img');
}
$icon.attr('src', commands[cmd]);
}
self.settings.content.icon = commands[command];
break;
case "progress":
var newDelay = self.settings.delay - (self.settings.delay * (commands[cmd] / 100));
this.$ele.data('notify-delay', newDelay);
this.$ele.find('[data-notify="progressbar"] > div').attr('aria-valuenow', commands[cmd]).css('width', commands[cmd] + '%');
break;
case "url":
this.$ele.find('[data-notify="url"]').attr('href', commands[cmd]);
break;
case "target":
this.$ele.find('[data-notify="url"]').attr('target', commands[cmd]);
break;
default:
this.$ele.find('[data-notify="' + cmd + '"]').html(commands[cmd]);
}
}
var posX = this.$ele.outerHeight() + parseInt(self.settings.spacing) + parseInt(self.settings.offset.y);
self.reposition(posX);
},
close: function() {
self.close();
}
};
},
buildNotify: function() {
var content = this.settings.content;
this.$ele = $(String.format(this.settings.template, this.settings.type, content.title, content.message, content.url, content.target));
this.$ele.attr('data-notify-position', this.settings.placement.from + '-' + this.settings.placement.align);
if (!this.settings.allow_dismiss) {
this.$ele.find('[data-notify="dismiss"]').css('display', 'none');
}
if ((this.settings.delay <= 0 && !this.settings.showProgressbar) || !this.settings.showProgressbar) {
this.$ele.find('[data-notify="progressbar"]').remove();
}
},
setIcon: function() {
this.$ele.addClass('alert-with-icon');
if (this.settings.icon_type.toLowerCase() === 'class') {
this.$ele.find('[data-notify="icon"]').addClass(this.settings.content.icon);
} else {
if (this.$ele.find('[data-notify="icon"]').is('img')) {
this.$ele.find('[data-notify="icon"]').attr('src', this.settings.content.icon);
} else {
this.$ele.find('[data-notify="icon"]').append('<img src="' + this.settings.content.icon + '" alt="Notify Icon" />');
}
}
},
styleDismiss: function() {
this.$ele.find('[data-notify="dismiss"]').css({
position: 'absolute',
right: '10px',
top: '50%',
marginTop: '-13px',
zIndex: this.settings.z_index + 2
});
},
styleURL: function() {
this.$ele.find('[data-notify="url"]').css({
backgroundImage: 'url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)',
height: '100%',
left: 0,
position: 'absolute',
top: 0,
width: '100%',
zIndex: this.settings.z_index + 1
});
},
placement: function() {
var self = this,
offsetAmt = this.settings.offset.y,
css = {
display: 'inline-block',
margin: '0px auto',
position: this.settings.position ? this.settings.position : (this.settings.element === 'body' ? 'fixed' : 'absolute'),
transition: 'all .5s ease-in-out',
zIndex: this.settings.z_index
},
hasAnimation = false,
settings = this.settings;
$('[data-notify-position="' + this.settings.placement.from + '-' + this.settings.placement.align + '"]:not([data-closing="true"])').each(function() {
offsetAmt = Math.max(offsetAmt, parseInt($(this).css(settings.placement.from)) + parseInt($(this).outerHeight()) + parseInt(settings.spacing));
});
if (this.settings.newest_on_top === true) {
offsetAmt = this.settings.offset.y;
}
css[this.settings.placement.from] = offsetAmt + 'px';
switch (this.settings.placement.align) {
case "left":
case "right":
css[this.settings.placement.align] = this.settings.offset.x + 'px';
break;
case "center":
css.left = 0;
css.right = 0;
break;
}
this.$ele.css(css).addClass(this.settings.animate.enter);
$.each(Array('webkit-', 'moz-', 'o-', 'ms-', ''), function(index, prefix) {
self.$ele[0].style[prefix + 'AnimationIterationCount'] = 1;
});
$(this.settings.element).append(this.$ele);
if (this.settings.newest_on_top === true) {
offsetAmt = (parseInt(offsetAmt) + parseInt(this.settings.spacing)) + this.$ele.outerHeight();
this.reposition(offsetAmt);
}
if ($.isFunction(self.settings.onShow)) {
self.settings.onShow.call(this.$ele);
}
this.$ele.one(this.animations.start, function() {
hasAnimation = true;
}).one(this.animations.end, function() {
self.$ele.removeClass(self.settings.animate.enter);
if ($.isFunction(self.settings.onShown)) {
self.settings.onShown.call(this);
}
});
setTimeout(function() {
if (!hasAnimation) {
if ($.isFunction(self.settings.onShown)) {
self.settings.onShown.call(this);
}
}
}, 600);
},
bind: function() {
var self = this;
this.$ele.find('[data-notify="dismiss"]').on('click', function() {
self.close();
});
if ($.isFunction(self.settings.onClick)) {
this.$ele.on('click', function(event) {
if (event.target != self.$ele.find('[data-notify="dismiss"]')[0]) {
self.settings.onClick.call(this, event);
}
});
}
this.$ele.mouseover(function() {
$(this).data('data-hover', "true");
}).mouseout(function() {
$(this).data('data-hover', "false");
});
this.$ele.data('data-hover', "false");
if (this.settings.delay > 0) {
self.$ele.data('notify-delay', self.settings.delay);
var timer = setInterval(function() {
var delay = parseInt(self.$ele.data('notify-delay')) - self.settings.timer;
if ((self.$ele.data('data-hover') === 'false' && self.settings.mouse_over === "pause") || self.settings.mouse_over != "pause") {
var percent = ((self.settings.delay - delay) / self.settings.delay) * 100;
self.$ele.data('notify-delay', delay);
self.$ele.find('[data-notify="progressbar"] > div').attr('aria-valuenow', percent).css('width', percent + '%');
}
if (delay <= -(self.settings.timer)) {
clearInterval(timer);
self.close();
}
}, self.settings.timer);
}
},
close: function() {
var self = this,
posX = parseInt(this.$ele.css(this.settings.placement.from)),
hasAnimation = false;
this.$ele.attr('data-closing', 'true').addClass(this.settings.animate.exit);
self.reposition(posX);
if ($.isFunction(self.settings.onClose)) {
self.settings.onClose.call(this.$ele);
}
this.$ele.one(this.animations.start, function() {
hasAnimation = true;
}).one(this.animations.end, function() {
$(this).remove();
if ($.isFunction(self.settings.onClosed)) {
self.settings.onClosed.call(this);
}
});
setTimeout(function() {
if (!hasAnimation) {
self.$ele.remove();
if (self.settings.onClosed) {
self.settings.onClosed(self.$ele);
}
}
}, 600);
},
reposition: function(posX) {
var self = this,
notifies = '[data-notify-position="' + this.settings.placement.from + '-' + this.settings.placement.align + '"]:not([data-closing="true"])',
$elements = this.$ele.nextAll(notifies);
if (this.settings.newest_on_top === true) {
$elements = this.$ele.prevAll(notifies);
}
$elements.each(function() {
$(this).css(self.settings.placement.from, posX);
posX = (parseInt(posX) + parseInt(self.settings.spacing)) + $(this).outerHeight();
});
}
});
$.notify = function(content, options) {
var plugin = new Notify(this, content, options);
return plugin.notify;
};
$.notifyDefaults = function(options) {
defaults = $.extend(true, {}, defaults, options);
return defaults;
};
$.notifyClose = function(selector) {
if (typeof selector === "undefined" || selector === "all") {
$('[data-notify]').find('[data-notify="dismiss"]').trigger('click');
} else if (selector === 'success' || selector === 'info' || selector === 'warning' || selector === 'danger') {
$('.alert-' + selector + '[data-notify]').find('[data-notify="dismiss"]').trigger('click');
} else if (selector) {
$(selector + '[data-notify]').find('[data-notify="dismiss"]').trigger('click');
} else {
$('[data-notify-position="' + selector + '"]').find('[data-notify="dismiss"]').trigger('click');
}
};
$.notifyCloseExcept = function(selector) {
if (selector === 'success' || selector === 'info' || selector === 'warning' || selector === 'danger') {
$('[data-notify]').not('.alert-' + selector).find('[data-notify="dismiss"]').trigger('click');
} else {
$('[data-notify]').not(selector).find('[data-notify="dismiss"]').trigger('click');
}
};
}));

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
var __assign=this&&this.__assign||function(){return(__assign=Object.assign||function(t){for(var i,a=1,s=arguments.length;a<s;a++)for(var n in i=arguments[a])Object.prototype.hasOwnProperty.call(i,n)&&(t[n]=i[n]);return t}).apply(this,arguments)},CountUp=function(){function t(t,i,a){var s=this;this.target=t,this.endVal=i,this.options=a,this.version="2.0.7",this.defaults={startVal:0,decimalPlaces:0,duration:2,useEasing:!0,useGrouping:!0,smartEasingThreshold:999,smartEasingAmount:333,separator:",",decimal:".",prefix:"",suffix:""},this.finalEndVal=null,this.useEasing=!0,this.countDown=!1,this.error="",this.startVal=0,this.paused=!0,this.count=function(t){s.startTime||(s.startTime=t);var i=t-s.startTime;s.remaining=s.duration-i,s.useEasing?s.countDown?s.frameVal=s.startVal-s.easingFn(i,0,s.startVal-s.endVal,s.duration):s.frameVal=s.easingFn(i,s.startVal,s.endVal-s.startVal,s.duration):s.countDown?s.frameVal=s.startVal-(s.startVal-s.endVal)*(i/s.duration):s.frameVal=s.startVal+(s.endVal-s.startVal)*(i/s.duration),s.countDown?s.frameVal=s.frameVal<s.endVal?s.endVal:s.frameVal:s.frameVal=s.frameVal>s.endVal?s.endVal:s.frameVal,s.frameVal=Number(s.frameVal.toFixed(s.options.decimalPlaces)),s.printValue(s.frameVal),i<s.duration?s.rAF=requestAnimationFrame(s.count):null!==s.finalEndVal?s.update(s.finalEndVal):s.callback&&s.callback()},this.formatNumber=function(t){var i,a,n,e,r,o=t<0?"-":"";if(i=Math.abs(t).toFixed(s.options.decimalPlaces),n=(a=(i+="").split("."))[0],e=a.length>1?s.options.decimal+a[1]:"",s.options.useGrouping){r="";for(var l=0,h=n.length;l<h;++l)0!==l&&l%3==0&&(r=s.options.separator+r),r=n[h-l-1]+r;n=r}return s.options.numerals&&s.options.numerals.length&&(n=n.replace(/[0-9]/g,function(t){return s.options.numerals[+t]}),e=e.replace(/[0-9]/g,function(t){return s.options.numerals[+t]})),o+s.options.prefix+n+e+s.options.suffix},this.easeOutExpo=function(t,i,a,s){return a*(1-Math.pow(2,-10*t/s))*1024/1023+i},this.options=__assign(__assign({},this.defaults),a),this.formattingFn=this.options.formattingFn?this.options.formattingFn:this.formatNumber,this.easingFn=this.options.easingFn?this.options.easingFn:this.easeOutExpo,this.startVal=this.validateValue(this.options.startVal),this.frameVal=this.startVal,this.endVal=this.validateValue(i),this.options.decimalPlaces=Math.max(this.options.decimalPlaces),this.resetDuration(),this.options.separator=String(this.options.separator),this.useEasing=this.options.useEasing,""===this.options.separator&&(this.options.useGrouping=!1),this.el="string"==typeof t?document.getElementById(t):t,this.el?this.printValue(this.startVal):this.error="[CountUp] target is null or undefined"}return t.prototype.determineDirectionAndSmartEasing=function(){var t=this.finalEndVal?this.finalEndVal:this.endVal;this.countDown=this.startVal>t;var i=t-this.startVal;if(Math.abs(i)>this.options.smartEasingThreshold){this.finalEndVal=t;var a=this.countDown?1:-1;this.endVal=t+a*this.options.smartEasingAmount,this.duration=this.duration/2}else this.endVal=t,this.finalEndVal=null;this.finalEndVal?this.useEasing=!1:this.useEasing=this.options.useEasing},t.prototype.start=function(t){this.error||(this.callback=t,this.duration>0?(this.determineDirectionAndSmartEasing(),this.paused=!1,this.rAF=requestAnimationFrame(this.count)):this.printValue(this.endVal))},t.prototype.pauseResume=function(){this.paused?(this.startTime=null,this.duration=this.remaining,this.startVal=this.frameVal,this.determineDirectionAndSmartEasing(),this.rAF=requestAnimationFrame(this.count)):cancelAnimationFrame(this.rAF),this.paused=!this.paused},t.prototype.reset=function(){cancelAnimationFrame(this.rAF),this.paused=!0,this.resetDuration(),this.startVal=this.validateValue(this.options.startVal),this.frameVal=this.startVal,this.printValue(this.startVal)},t.prototype.update=function(t){cancelAnimationFrame(this.rAF),this.startTime=null,this.endVal=this.validateValue(t),this.endVal!==this.frameVal&&(this.startVal=this.frameVal,this.finalEndVal||this.resetDuration(),this.finalEndVal=null,this.determineDirectionAndSmartEasing(),this.rAF=requestAnimationFrame(this.count))},t.prototype.printValue=function(t){var i=this.formattingFn(t);"INPUT"===this.el.tagName?this.el.value=i:"text"===this.el.tagName||"tspan"===this.el.tagName?this.el.textContent=i:this.el.innerHTML=i},t.prototype.ensureNumber=function(t){return"number"==typeof t&&!isNaN(t)},t.prototype.validateValue=function(t){var i=Number(t);return this.ensureNumber(i)?i:(this.error="[CountUp] invalid start or end value: "+t,null)},t.prototype.resetDuration=function(){this.startTime=null,this.duration=1e3*Number(this.options.duration),this.remaining=this.duration},t}();

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

@@ -0,0 +1,55 @@
<!-- a lot of stuff-->
<!doctype html>
{% load static %}
<html lang="en"">
<head>
<title>Contract Detail</title>
<link href="{% static 'financial/css/material-dashboard.css' %}" rel="stylesheet" >
<link rel="icon" type="image/xicon" href="{% static 'public/img/logo.png' %}">
<body class="g-sidenav-show bg-gray-200" >
<main class="main-content position-relative max-height-vh-100 h-100 border-radius-lg">
{% if is_new %}
<h1>New Contract</h1>
<form method="post" action='{% url "new_contract" %}' >
{% csrf_token %}
{{ form }}
<button type=""button" value="submit">Create</button>
</form>
{% else %}
<h1> {{ contract.name }}</h1>
<form method="post" action='{% url "contract_detail" contract.slug %}' >
{% csrf_token %}
{{ form }}
<button type=""button" value="submit">Update</button>
</form>
{% endif %}
{% if is_new %}
{% else %}
<h2> Charge Numbers</h2>
{% if charge_numbes %}
<p> put charge number table here</p>
<p> Create a new charge number</p>
{{ charge_number_form }}
{% else %}
<p> There are no charge numbers for this contract</p>
<form method="post" action='{% url "new_charge_number" %}' >
{% csrf_token %}
{{ charge_number_form }}
<button type=""button" value="submit">Update</button>
</form>
{% endif %}
{% endif %}
</body>

View File

@@ -0,0 +1,49 @@
<!-- a lot of stuff-->
<!doctype html>
{% load static %}
<html lang="en"">
<head>
<title>Profile</title>
<link href="{% static 'financial/css/material-dashboard.css' %}" rel="stylesheet" >
<link rel="icon" type="image/xicon" href="{% static 'public/img/logo.png' %}">
<body class="g-sidenav-show bg-gray-200" >
<main class="main-content position-relative max-height-vh-100 h-100 border-radius-lg">
<h1>Contracts</h1>
{% if contracts %}
<table>
<tr>
<th>Name</th>
<th>Identifier</th>
<th>Type</th>
<th>Start Date</th>
<th>End Date</th>
<th>Proposed Amount</th>
<th>Baseline Amount</th>
<th>Funded Amount</th>
</tr>
{% for contract in contracts %}
<tr>
<td> <a href="{% url 'contract_detail' contract.slug %}">{{ contract.name }}</a></td>
<td> {{ contract.slug }}</td>
<td> {{ contract.contract_type }}</td>
<td> {{ contract.baseline_start }}</td>
<td> {{ contract.baseline_end }}</td>
<td> {{ contract.proposed_amount }}</td>
<td> {{ contract.baseline_amount }}</td>
<td> {{ contract.funded_amount }}</td>
</tr>
{% endfor %}
</table>
<hr>
<p> Create <a href="{% url 'new_contract' %}">new</a> contract.</p>
{% else %}
<p> There are no contracts. <a href="{% url 'new_contract' %}">Please make one</a></p>
{% endif %}
</body>

View File

@@ -0,0 +1,116 @@
<!doctype html>
{% load static %}
<html lang="en"">
<head>
<title>Accounting</title>
<link href="{% static 'financial/css/material-dashboard.css' %}" rel="stylesheet" >
<link rel="icon" type="image/xicon" href="{% static 'public/img/logo.png' %}">
<body class="g-sidenav-show bg-gray-200" >
<div class="sidenav-header">
<ul class="navbar-item">
<li class="nav-item">
Dashboard
</li>
<li class="nav-item">
Settings
</li>
</ul>
</div>
<main class="main-content position-relative max-height-vh-100 h-100 border-radius-lg">
<nav class="navbar navbar-main navbar-expand-lg px-0 mx-4 shadow-none border-radius-xl" id="navbarBlur" data-scroll="true">
<div class="container-fluid py-1 px-3">
<nav aria-label="breadcrumb">
<h6>Dashboard</h6>
</nav>
</div>
</nav>
<div class="container-fluid py-4">
<div class="row">
<div class="col-xl-3 col-sm-4 mb-xl-o mb-4">
<div class="card">
<div class="card-header p-3 pt-2">
<a href="{% url 'contracts' %}">
Contracts
</a>
</div>
</div class="card-body">
<p> put picture here</p>
</div>
</div>
</div>
{% if is_worker %}
<div class="col-xl-3 col-sm-4 mb-xl-o mb-4">
<div class="card">
<div class="card-header p-3 pt-2">
<a href="{% url 'profile' %}">
Profile
</a>
</div>
</div class="card-body">
<p> put picture here</p>
</div>
</div>
</div>
{% endif %}
{% if is_worker %}
<div class="col-xl-3 col-sm-4 mb-xl-o mb-4">
<div class="card">
<div class="card-header p-3 pt-2">
<a href="{% url 'Timekeeping' %}">
Timekeeping
</a>
</div>
</div class="card-body">
<p> put picture here</p>
</div>
</div>
</div>
{% endif %}
{% if is_manager %}
<div class="col-xl-3 col-sm-4 mb-xl-o mb-4">
<div class="card">
<div class="card-header p-3 pt-2">
<a href="{% url 'Timeapproval' %}">
Time Approval
</a>
</div>
<div class="card-body">
<p> put picture here</p>
</div>
</div>
</div>
{% endif %}
{% if is_procurment_officer %}
<div class="col-xl-3 col-sm-4 mb-xl-o mb-4">
<div class="card">
<div class="card-header p-3 pt-2">
</div>
<div class="card-body">
<p> put picture here</p>
</div>
</div>
</div>
{% endif %}
{% if is_finance %}
<div class="col-xl-3 col-sm-4 mb-xl-o mb-4">
<div class="card">
<div class="card-header p-3 pt-2">
<a href="{% url 'contracts' %}">
Contracts
</a>
</div>
<div class="card-body">
<p> put picture here</p>
</div>
</div>
</div>
{% endif %}
</div>
</div>
</main>
<h1>Accouting</h1>
</body>

View File

@@ -0,0 +1 @@
<p> this page has not been created yet</p>

View File

@@ -0,0 +1,17 @@
<!-- a lot of stuff-->
<!doctype html>
{% load static %}
<html lang="en"">
<head>
<title>Profile</title>
<link href="{% static 'financial/css/material-dashboard.css' %}" rel="stylesheet" >
<link rel="icon" type="image/xicon" href="{% static 'public/img/logo.png' %}">
<body class="g-sidenav-show bg-gray-200" >
<main class="main-content position-relative max-height-vh-100 h-100 border-radius-lg">
<h1>Profile</h1>
{{ form }}
</body>

View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@@ -0,0 +1,17 @@
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="financial_index"),
path("timekeeping", views.timekeeping, name="Timekeeping"),
path("timeapproval", views.timeapproval, name="Timeapproval"),
path("contracts", views.contracts, name="contracts"),
path("<str:contract_slug>/contract_detail", views.contract_detail, name="contract_detail"),
path("new_contract", views.new_contract, name="new_contract"),
path("new_charge_number", views.new_charge_number, name="new_charge_number"),
path("<str:charge_number_slug>/update_charge_number", views.update_charge_number, name="update_charge_number"),
#path("contracts/<int:contract_id>/", views.contract_detail, name="contract"),
path("procurements", views.procurement, name="procurements"),
path("profile", views.profile, name="profile"),
]

View File

@@ -0,0 +1,79 @@
from django.shortcuts import render, redirect
from .forms import EmployeeForm, ContractForm, ChargeNumberForm
from .models import Contract
# Create your views here.
# PAGES TO CREATE
# dashboard
# log in
# log out
# password reset
# employee timecard
# time card approval
# contract
# charge number
# user management (?)
def index(request):
permissions = []
context = {
'is_procurment_officer':True,
'is_worker':True,
'is_manager':True,
'is_finance': True
}
return render(request, "financial/index.html", context)
def contracts(request):
contracts = Contract.objects.all()
return render(request, 'financial/contracts.html', {'contracts':contracts})
def contract_detail(request, contract_slug):
contract = Contract.objects.filter(slug=contract_slug)
if request.method == 'POST':
form = ContractForm(request.POST, instance=contract[0])
if form.is_valid():
form.save()
return redirect('contracts')
else:
form = ContractForm(instance = contract[0])
charge_number_form = ChargeNumberForm()
# TODO: handle multiple better but we can assume there is only one
return render(request, 'financial/contract_detail.html', {'is_new': False, 'form': form, 'charge_number_form':charge_number_form, 'contract': contract[0]})
def new_contract(request):
if request.method == "POST":
form = ContractForm(request.POST)
if form.is_valid():
form.save()
return redirect('contracts')
else:
return render(request, 'financial/contract_detail.html', {"form": ContractForm(), 'is_new': True})
else:
return render(request, 'financial/contract_detail.html', {"form": ContractForm(), 'is_new': True})
def update_charge_number(request, charge_number_slug):
return render(request, 'financial/not_created.html', {})
def new_charge_number(request, charge_number_slug):
return render(request, 'financial/not_created.html', {})
def timekeeping(request):
return render(request, 'financial/not_created.html', {})
def timeapproval(request):
return render(request, 'financial/not_created.html', {})
def chargenumber(request):
return render(request, 'financial/not_created.html', {})
def procurement(request):
return render(request, 'financial/procurement.html', {})
def profile(request):
form = EmployeeForm()
return render(request, 'financial/profile.html', {'form': form})
# def contract_detail(request, contract_id):

22
company_site/manage.py Executable file
View File

@@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'company_site.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

View File

View File

@@ -0,0 +1,64 @@
from django.contrib import admin
from .models import Contact, EmailMessage
from .views import preview_email
from django.shortcuts import render, get_object_or_404
from django.urls import path
from django.template.loader import get_template
from django.core.mail import EmailMultiAlternatives
# Register your models here.
@admin.register(Contact, site=admin.site)
class ContactAdmin(admin.ModelAdmin):
list_display = ("email", "name", "contacted")
list_filter = ("email", "name", "contacted")
search_fields = ("email", "name")
@admin.action(description='Send seelcted emails')
def send_emails(modeladmin, request, queryset):
for email in queryset:
success_count: int = 0
try:
from_email="info@aimloperations.com"
d={"title":email.subject,"content":email.body}
html_content = get_template(f"emails/marketing_email.html").render(d)
text_content = get_template(f"emails/marketing_email.txt").render(d)
msg = EmailMultiAlternatives(email.subject, text_content, from_email, [email.recipient])
msg.attach_alternative(html_content, "text/html")
msg.send(fail_silently=False)
email.sent = True
email.save()
success_count += 1
except Exception as e:
raise UserWarning(e)
modeladmin.message_user(request, f"{success_count} emails sent successfully.")
@admin.register(EmailMessage, site=admin.site)
class EmailMessageAdmin(admin.ModelAdmin):
change_form_template = 'admin/public/emailmessage/change_form.html'
list_display = ('subject', 'recipient', 'sent')
actions = [send_emails]
def get_urls(self):
urls = super().get_urls()
custom_urls = [
path('preview_email/<int:pk>/', self.admin_site.admin_view(self.preview_email), name="preview_email")
]
print(f'RETURNING: {custom_urls + urls}')
return custom_urls + urls
def preview_email(self, request, pk):
email_instance = get_object_or_404(EmailMessage, pk=pk)
context = {
"title":email_instance.subject,
"content":email_instance.body
}
return render(
request, 'public/preview_email.html', context
)

View File

@@ -0,0 +1,6 @@
from django.apps import AppConfig
class PublicConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'public'

View File

@@ -0,0 +1,15 @@
from django import forms
from django_recaptcha.fields import ReCaptchaField
from django_recaptcha.widgets import ReCaptchaV3
from django.conf import settings
class FormWithCaptcha(forms.Form):
captcha = ReCaptchaField(
widget=ReCaptchaV3(
attrs={
'required_score':0.85,
}
),
public_key=settings.RECAPTCHA_PUBLIC_KEY,
private_key=settings.RECAPTCHA_PRIVATE_KEY,
)

View File

@@ -0,0 +1,23 @@
# Generated by Django 5.0 on 2023-12-05 18:32
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Contact',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('email', models.EmailField(max_length=128)),
('name', models.CharField(max_length=128)),
('blurb', models.CharField(blank=True, max_length=254)),
],
),
]

View File

@@ -0,0 +1,24 @@
# Generated by Django 5.0 on 2023-12-05 19:28
import django.utils.timezone
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('public', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='contact',
name='created',
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name='contact',
name='last_modified',
field=models.DateTimeField(default=django.utils.timezone.now),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.0 on 2023-12-07 17:23
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('public', '0002_contact_created_contact_last_modified'),
]
operations = [
migrations.AddField(
model_name='contact',
name='contacted',
field=models.BooleanField(default=False),
),
]

View File

@@ -0,0 +1,19 @@
# Generated by Django 4.2.17 on 2025-02-10 17:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("public", "0003_contact_contacted"),
]
operations = [
migrations.AddField(
model_name="contact",
name="subject",
field=models.CharField(default=" ", max_length=128),
preserve_default=False,
),
]

View File

@@ -0,0 +1,40 @@
# Generated by Django 4.2.17 on 2025-02-16 12:43
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
("public", "0004_contact_subject"),
]
operations = [
migrations.CreateModel(
name="EmailMessage",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created", models.DateTimeField(default=django.utils.timezone.now)),
(
"last_modified",
models.DateTimeField(default=django.utils.timezone.now),
),
("subject", models.CharField(max_length=255)),
("body", models.TextField()),
("recipient", models.EmailField(max_length=254)),
("sent", models.BooleanField(default=False)),
],
options={
"abstract": False,
},
),
]

View File

@@ -0,0 +1,35 @@
from django.db import models
from django.utils import timezone
class TimeInfoBase(models.Model):
created = models.DateTimeField(default=timezone.now)
last_modified = models.DateTimeField(default=timezone.now)
class Meta:
abstract = True
def save(self, *args, **kwargs):
if not kwargs.pop("skip_last_modified", False) and not hasattr(self, "skip_last_modified"):
self.last_modified = timezone.now()
if kwargs.get("update_fields") is not None:
kwargs["update_fields"] = list({*kwargs["update_fields"], "last_modified"})
super().save(*args, **kwargs)
# Create your models here.
class Contact(TimeInfoBase):
email = models.EmailField(max_length=128)
name = models.CharField(max_length=128)
blurb = models.CharField(max_length=254, blank=True)
subject = models.CharField(max_length=128)
contacted = models.BooleanField(default=False)
class EmailMessage(TimeInfoBase):
subject = models.CharField(max_length=255)
body = models.TextField()
recipient = models.EmailField()
sent = models.BooleanField(default=False)
def __str__(self):
return self.recipient + " | " + self.subject

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 978 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1012 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,15 @@
{% extends 'admin/change_form.html' %}
{% block submit_buttons_bottom %}
<div class="submit-row">
<!-- <input type="submit" value="Preview Email" name="_preview_email" class="default" /> -->
<form action="/public/emailmessage/preview_email/{{ original.pk }}/" method="post" target="_blank" style="display: inline;">
{% csrf_token %}
<input type="submit" value="Preview Email" name="_preview_email" class="default" />
</form>
</div>
{{ block.super }}
{% endblock %}

View File

@@ -0,0 +1,147 @@
<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI ML Operations, LLC</title>
<!-- Materialize CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css" rel="stylesheet">
<link rel="icon" type="image/xicon" href="{% static 'public/img/logo.png' %}">
<!-- Material Icons -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!-- Custom CSS -->
<style>
.hero-section {
background: {% block path %}url({% static 'public/img/bg1.png' %}) {% endblock %};
height: 60vh;
display: flex;
background-repeat:no-repeat;
background-position: center center;
align-items: center;
justify-content: center;
flex-direction: column;
color: white;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
}
.hero-section h1 {
font-size: 4rem;
font-weight: bold;
}
.hero-section p {
font-weight: bold;
}
.section {
padding: 4rem 0;
}
feature-icon {
font-size: 3rem;
color: #26a69a;
}
.pricing-card {
text-align: center;
padding: 2rem;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.screenshot-img {
width: 100%;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.footer {
padding: 2rem 0;
background-color: #333;
color: white;
text-align: center;
}
body {
display: flex;
min-height: 100vh;
flex-direction: column;
}
main {
flex: 1 0 auto;
}
</style>
</head>
<body>
<!-- Navigation Bar -->
<ul id="servicesDropdown" class="dropdown-content">
<li ><a href="{% url 'ai_education' %}">AI Education</a></li>
<li ><a href="{% url 'ai_sensor' %}">AI Sensor</a></li>
<li ><a href="{% url 'bot' %}">Bot Creation</a></li>
<li class="active"><a href="{% url 'chat' %}">Chat</a></li>
<li ><a href="{% url 'computers' %}">Computer Builds</a></li>
<li ><a href="{% url 'file_hosting' %}">File Hosting</a></li>
<li ><a href="{% url 'ml_model' %}">ML Models</a></li>
<li ><a href="{% url 'web_design' %}">Website Design</a></li>
</ul>
<nav class="blue-grey darken-3">
<div class="nav-wrapper container">
<a href="{% url 'public_index' %}" class="brand-logo">AI ML Operations, LLC</a>
<a href="#" data-target="mobile-nav" class="sidenav-trigger"><i class="material-icons">menu</i></a>
<ul class="right hide-on-med-and-down">
<!-- <li class="active"><a href="{% url 'public_index' %}">Home</a></li> -->
<li><a class="dropdown-trigger" href="#!" data-target="servicesDropdown">Services<i class="material-icons right">arrow_drop_down</i></a></li>
<li><a href="{% url 'contact' %}">Contact</a></li>
</ul>
</div>
</nav>
<!-- Mobile Navigation -->
<ul class="sidenav" id="mobile-nav">
<li class="active"><a >Services</a></li>
<hr />
<li ><a href="{% url 'ai_education' %}">AI Education</a></li>
<li ><a href="{% url 'ai_sensor' %}">AI Sensor</a></li>
<li ><a href="{% url 'bot' %}">Bot Creation</a></li>
<li ><a href="{% url 'chat' %}">Chat</a></li>
<li ><a href="{% url 'computers' %}">Computer Builds</a></li>
<li ><a href="{% url 'file_hosting' %}">File Hosting</a></li>
<li ><a href="{% url 'ml_model' %}">ML Models</a></li>
<li ><a href="{% url 'web_design' %}">Website Design</a></li>
<hr/>
<li class="active"><a href="{% url 'contact' %}">Contact</a></li>
</ul>
</ul>
<main>
{% block content %}
{% endblock %}
</main>
<!-- Footer -->
<footer class="footer">
<div class="container">
<p>&copy; <script>document.write( new Date().getFullYear() );</script> AI ML Operations, LLC. All rights reserved.</p>
</div>
</footer>
<!-- Materialize JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<!-- <script>
// Initialize Materialize components
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('.sidenav');
var instances = M.Sidenav.init(elems);
});
</script>
<script>
$(".dropdown-trigger").dropdown();
</script> -->
<script>
$(".dropdown-trigger").dropdown();
</script>
<script>
// Initialize Materialize components
M.AutoInit();
</script>
</body>
</html>

View File

@@ -0,0 +1,110 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>New Feedback Submission</title>
<style>
/* Basic reset for email clients */
body, table, td, a {
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
table, td {
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
img {
border: 0;
height: auto;
line-height: 100%;
outline: none;
text-decoration: none;
-ms-interpolation-mode: bicubic;
}
body {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
background-color: #f4f4f4;
}
.email-container {
max-width: 600px;
margin: 0 auto;
background-color: #ffffff;
border: 1px solid #dddddd;
}
.header {
background-color: #007BFF;
color: #ffffff;
padding: 20px;
text-align: center;
}
.content {
padding: 20px;
color: #333333;
}
.footer {
background-color: #f4f4f4;
color: #777777;
text-align: center;
padding: 10px;
font-size: 12px;
}
.feedback-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 10px;
}
.feedback-text {
font-size: 14px;
line-height: 1.5;
}
</style>
</head>
<body>
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" align="center">
<tr>
<td>
<!-- Email Container -->
<div class="email-container">
<!-- Header -->
<div class="header">
<h1>New Contact Request</h1>
</div>
<!-- Content -->
<div class="content">
<p>Hello,</p>
<p>A new feedback item has been submitted. Here are the details:</p>
<!-- Feedback Title -->
<div class="feedback-title">
Subject: <strong>{{ subject }}</strong>
</div>
<!-- Email -->
<div class="feedback-title">
Email: <strong>{{ email }}</strong>
</div>
<!-- Feedback Text -->
<div class="feedback-text">
<strong>Message:</strong><br>
{{ message }}
</div>
<p>Thank you for your attention.</p>
</div>
<!-- Footer -->
<div class="footer">
<p>This is an automated message. Please do not reply to this email.</p>
<p>&copy; 2025 AI ML Operations, LLC. All rights reserved.</p>
</div>
</div>
</td>
</tr>
</table>
</body>
</html>

View File

@@ -0,0 +1,3 @@
New Contact Request for AI ML Operations, LLC
"New Contact. {{ subject }} from {{ email }}. {{ message }}"

View File

@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Email Template</title>
<!-- Materialize CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css" rel="stylesheet">
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
}
.email-container {
max-width: 600px;
margin: 0 auto;
background-color: #ffffff;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.header {
background-color: #37474f;
color: #ffffff;
padding: 20px;
text-align: center;
}
.content {
padding: 20px;
color: #333333;
}
.footer {
background-color: #333;
padding: 10px;
text-align: center;
font-size: 12px;
color: white;
}
</style>
</head>
<body>
<div class="email-container">
<!-- Header -->
<div class="header">
<h4>{{ title | safe }}</h4>
</div>
<!-- Content -->
<div class="content">
{{ content | safe }}
</div>
<!-- Footer -->
<div class="footer">
<p>© 2025 AI ML Operations, LLC. All rights reserved.</p>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,3 @@
{{ subject }}
{{ content }}

View File

@@ -0,0 +1,98 @@
{% extends "base.html" %}
{% load static %}
{% block path %} url({% static 'public/img/bg4.jpeg' %}) {% endblock %}
{% block content %}
<!-- Hero Section -->
<div class="hero-section">
<h1>AI Education</h1>
<p class="flow-text">Empowering Businesses with AI Knowledge</p>
</div>
<!-- About AI Education Section -->
<div class="section white">
<div class="row container">
<h2 class="header">About AI Education</h2>
<p class="flow-text">
At AI ML Operations, we believe that understanding AI is the first step toward leveraging its power. Our AI Education service is designed to equip businesses with the knowledge and skills needed to integrate AI into their workflows effectively. We offer tailored courses, hands-on workshops, and ongoing support to ensure your team is confident and capable in using AI technologies.
</p>
</div>
</div>
<!-- Features Section -->
<div class="section grey lighten-3">
<div class="row container">
<h2 class="header">What We Offer</h2>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">school</i>
<h5>Custom Courses</h5>
<p>Tailored AI courses designed to meet your business needs and goals.</p>
</div>
</div>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">work</i>
<h5>Hands-On Workshops</h5>
<p>Interactive sessions to apply AI concepts in real-world scenarios.</p>
</div>
</div>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">support</i>
<h5>Ongoing Support</h5>
<p>Continuous learning and support to keep your team up-to-date.</p>
</div>
</div>
</div>
</div>
<!-- Course Highlights Section -->
<div class="section white">
<div class="row container">
<h2 class="header">Course Highlights</h2>
<div class="col s12 m4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="AI Fundamentals">
</div>
<div class="card-content">
<span class="card-title">AI Fundamentals</span>
<p>Learn the basics of AI, including machine learning, neural networks, and data preprocessing.</p>
</div>
</div>
</div>
<div class="col s12 m4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="AI for Business">
</div>
<div class="card-content">
<span class="card-title">AI for Business</span>
<p>Discover how AI can optimize operations, improve decision-making, and drive innovation.</p>
</div>
</div>
</div>
<div class="col s12 m4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Advanced AI Techniques">
</div>
<div class="card-content">
<span class="card-title">Advanced AI Techniques</span>
<p>Dive deep into advanced topics like deep learning, natural language processing, and computer vision.</p>
</div>
</div>
</div>
</div>
</div>
<!-- Call to Action Section -->
<div class="section blue-grey darken-3 white-text">
<div class="row container center">
<h2 class="header">Ready to Transform Your Business?</h2>
<p class="flow-text">Contact us today to schedule your AI Education sessions.</p>
<a href="{% url 'contact' %}" class="btn-large waves-effect waves-light white blue-grey-text text-darken-3">Get Started</a>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,109 @@
{% extends "base.html" %}
{% load static %}
{% block path %} url({% static 'public/img/bg4.jpeg' %}) {% endblock %}
{% block content %}
<!-- Hero Section -->
<div class="hero-section">
<h1>AI Sensor Algorithms</h1>
<p class="flow-text">Enhancing Sensor Performance with Advanced AI</p>
</div>
<!-- About AI Sensor Algorithms Section -->
<div class="section white">
<div class="row container">
<h2 class="header">About AI Sensor Algorithms</h2>
<p class="flow-text">
At AI ML Operations, we specialize in developing cutting-edge AI algorithms to enhance the performance of on-board sensors. By leveraging techniques such as Natural Language Processing (NLP), Pattern Recognition, Machine Vision, and more, we enable sensors to deliver smarter, faster, and more accurate results. Our solutions are designed to integrate seamlessly into your systems, providing real-time insights and improving decision-making capabilities.
</p>
</div>
</div>
<!-- Features Section -->
<div class="section grey lighten-3">
<div class="row container">
<h2 class="header">What We Offer</h2>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">visibility</i>
<h5>Machine Vision</h5>
<p>Enhance visual data processing with advanced machine vision algorithms.</p>
</div>
</div>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">pattern</i>
<h5>Pattern Recognition</h5>
<p>Identify and analyze patterns in sensor data for improved accuracy.</p>
</div>
</div>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">translate</i>
<h5>Natural Language Processing</h5>
<p>Enable sensors to interpret and respond to human language inputs.</p>
</div>
</div>
</div>
</div>
<!-- Applications Section -->
<div class="section white">
<div class="row container">
<h2 class="header">Applications</h2>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Industrial Automation">
</div>
<div class="card-content">
<span class="card-title">Industrial Automation</span>
<p>Optimize manufacturing processes with AI-enhanced sensors.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Autonomous Vehicles">
</div>
<div class="card-content">
<span class="card-title">Autonomous Vehicles</span>
<p>Improve navigation and safety with advanced sensor algorithms.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Healthcare Monitoring">
</div>
<div class="card-content">
<span class="card-title">Healthcare Monitoring</span>
<p>Enable real-time health tracking with AI-powered sensors.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Smart Home Devices">
</div>
<div class="card-content">
<span class="card-title">Smart Home Devices</span>
<p>Enhance user experiences with intelligent sensor integrations.</p>
</div>
</div>
</div>
</div>
</div>
<!-- Call to Action Section -->
<div class="section blue-grey darken-3 white-text">
<div class="row container center">
<h2 class="header">Ready to Enhance Your Sensors?</h2>
<p class="flow-text">Contact us today to discuss your AI sensor needs.</p>
<a href="{% url 'contact' %}" class="btn-large waves-effect waves-light white blue-grey-text text-darken-3">Get Started</a>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,98 @@
{% extends "base.html" %}
{% load static %}
{% block path %} url({% static 'public/img/bg4.jpeg' %}) {% endblock %}
{% block content %}
<!-- Hero Section -->
<div class="hero-section">
<h1>Agentic Bots</h1>
<p class="flow-text">Intelligent Bots for Automation and Engagement</p>
</div>
<!-- About Agentic Bots Section -->
<div class="section white">
<div class="row container">
<h2 class="header">About Agentic Bots</h2>
<p class="flow-text">
At AI ML Operations, we create intelligent, agentic bots designed to automate tasks, engage users, and streamline workflows. Our bots currently integrate seamlessly with Telegram, but we can customize them to suit your specific platform or needs. Whether you need a bot for customer support, data collection, or process automation, we deliver solutions that are reliable, scalable, and easy to use.
</p>
</div>
</div>
<!-- Features Section -->
<div class="section grey lighten-3">
<div class="row container">
<h2 class="header">What We Offer</h2>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">smart_toy</i>
<h5>Custom Bot Development</h5>
<p>Tailored bots designed to meet your unique business requirements.</p>
</div>
</div>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">integration_instructions</i>
<h5>Platform Integration</h5>
<p>Bots that integrate with Telegram or other platforms of your choice.</p>
</div>
</div>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">settings</i>
<h5>Hosting & Maintenance</h5>
<p>We host and maintain your bots, ensuring they run smoothly 24/7.</p>
</div>
</div>
</div>
</div>
<!-- Applications Section -->
<div class="section white">
<div class="row container">
<h2 class="header">Applications</h2>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Customer Support">
</div>
<div class="card-content">
<span class="card-title">Customer Support</span>
<p>Automate responses and provide instant support to your customers.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Data Collection">
</div>
<div class="card-content">
<span class="card-title">Data Collection</span>
<p>Gather and organize data efficiently using intelligent bots.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Process Automation">
</div>
<div class="card-content">
<span class="card-title">Process Automation</span>
<p>Streamline workflows and reduce manual effort with automated bots.</p>
</div>
</div>
</div>
</div>
</div>
<!-- Call to Action Section -->
<div class="section blue-grey darken-3 white-text">
<div class="row container center">
<h2 class="header">Ready to Automate?</h2>
<p class="flow-text">Contact us today to create your custom agentic bot.</p>
<a href="{% url 'contact' %}" class="btn-large waves-effect waves-light white blue-grey-text text-darken-3">Get Started</a>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,96 @@
{% extends "base.html" %}
{% load static %}
{% block path %} url({% static 'public/img/bg4.jpeg' %}) {% endblock %}
{% block content %}
<!-- Hero Section -->
<div class="hero-section" >
<h1>Chat</h1>
<p>Your Private, Secure, and Powerful LLM Solution</p>
</div>
<!-- Product Description Section -->
<div class="section white">
<div class="row container">
<h2 class="header">What is Chat?</h2>
<p class="flow-text">
Chat is a closed-source Large Language Model (LLM) designed specifically for small and medium businesses. Hosted locally, Chat ensures that all your data remains private and secure. With Chat, your data is never sold or accessed by third parties—ever. You retain full control over your accounts and data. Chat also includes advanced file analysis capabilities, making it a versatile tool for your business needs.
</p>
</div>
</div>
<!-- Features Section -->
<div class="section grey lighten-3">
<div class="row container">
<h2 class="header">Key Features</h2>
<div class="col s12 m4">
<div class="center">
<i class="material-icons feature-icon">lock</i>
<h5>Local Hosting</h5>
<p>All data is stored and processed locally, ensuring maximum privacy and security.</p>
</div>
</div>
<div class="col s12 m4">
<div class="center">
<i class="material-icons feature-icon">security</i>
<h5>No Third-Party Access</h5>
<p>Your data is never sold or accessed by third parties for any reason.</p>
</div>
</div>
<div class="col s12 m4">
<div class="center">
<i class="material-icons feature-icon">folder</i>
<h5>File Analysis</h5>
<p>Analyze files directly within the platform for seamless integration into your workflows.</p>
</div>
</div>
</div>
</div>
<!-- Pricing Section -->
<div class="section white">
<div class="row container">
<h2 class="header">Pricing</h2>
<div class="col s12 m6">
<div class="screenshot-img">
<img src="{% static 'public/img/chat_screenshot.png' %}" style="width: 100%;">
</div>
</div>
<div class="col s12 m6">
<div class="pricing-card blue-grey lighten-5">
<h4>$10</h4>
<p>per user per month</p>
<p>Start with a free trial to experience the power of Chat.</p>
<a class="btn waves-effect waves-light" href="{% url 'contact' %}">Inquire Now</a>
</div>
</div>
</div>
</div>
<!-- Product Images Section -->
<!-- <div class="section grey lighten-3">
<div class="row container">
<h2 class="header">Product Images</h2>
<div class="col s12 m4">
<img src="https://via.placeholder.com/400x300" alt="Chat Interface" class="responsive-img materialboxed">
</div>
<div class="col s12 m4">
<img src="https://via.placeholder.com/400x300" alt="File Analysis" class="responsive-img materialboxed">
</div>
<div class="col s12 m4">
<img src="https://via.placeholder.com/400x300" alt="Dashboard" class="responsive-img materialboxed">
</div>
</div>
</div> -->
{% endblock %}

View File

@@ -0,0 +1,109 @@
{% extends "base.html" %}
{% load static %}
{% block path %} url({% static 'public/img/bg4.jpeg' %}) {% endblock %}
{% block content %}
<!-- Hero Section -->
<div class="hero-section">
<h1>Computer Solutions</h1>
<p class="flow-text">From Gaming PCs to AI Servers We Build, Deploy, and Maintain</p>
</div>
<!-- About Computer Solutions Section -->
<div class="section white">
<div class="row container">
<h2 class="header">About Our Computer Solutions</h2>
<p class="flow-text">
At AI ML Operations, we specialize in procuring, building, deploying, and maintaining computers tailored to your specific needs. Whether you're a gamer, a creative professional, or a business requiring high-performance workstations or AI servers, we deliver reliable, scalable, and efficient solutions. Our end-to-end service ensures your systems are optimized for performance and longevity.
</p>
</div>
</div>
<!-- Features Section -->
<div class="section grey lighten-3">
<div class="row container">
<h2 class="header">What We Offer</h2>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">build</i>
<h5>Custom Builds</h5>
<p>We design and build computers tailored to your specific requirements, from gaming PCs to AI servers.</p>
</div>
</div>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">cloud_upload</i>
<h5>Deployment</h5>
<p>Seamless deployment of systems, ensuring they are ready for immediate use.</p>
</div>
</div>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">settings</i>
<h5>Maintenance</h5>
<p>Ongoing support and maintenance to keep your systems running smoothly.</p>
</div>
</div>
</div>
</div>
<!-- Solutions Section -->
<div class="section white">
<div class="row container">
<h2 class="header">Our Solutions</h2>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Gaming PCs">
</div>
<div class="card-content">
<span class="card-title">Gaming PCs</span>
<p>High-performance gaming rigs built for the latest games and VR experiences.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Workstations">
</div>
<div class="card-content">
<span class="card-title">Workstations</span>
<p>Powerful workstations for creative professionals, engineers, and developers.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Storage Servers">
</div>
<div class="card-content">
<span class="card-title">Storage Servers</span>
<p>Scalable storage solutions for data-intensive applications and backups.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="AI Servers">
</div>
<div class="card-content">
<span class="card-title">AI Servers</span>
<p>High-performance servers optimized for AI and machine learning workloads.</p>
</div>
</div>
</div>
</div>
</div>
<!-- Call to Action Section -->
<div class="section blue-grey darken-3 white-text">
<div class="row container center">
<h2 class="header">Ready to Upgrade Your Systems?</h2>
<p class="flow-text">Contact us today to discuss your computer needs.</p>
<a href="{% url 'contact' %}" class="btn-large waves-effect waves-light white blue-grey-text text-darken-3">Get Started</a>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,126 @@
{% extends "base.html" %}
{% load static %}
{% block path %} url({% static 'public/img/bg2.jpeg' %}) {% endblock %}
{% block content %}
<!-- Hero Section -->
<div class="hero-section">
<h1>Get in Touch</h1>
</div>
<!-- Contact Content -->
<div class="contact-section grey lighten-3">
<div class="container">
<div class="row">
{% if success %}
<div class="alert alert-success alert-dismissible fade show" role="alert">
<span class="alert-text"> We'll be in contact shortly!</span>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endif %}
{% if errors %}
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<span class="alert-text">{{ errors }}</span>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endif %}
<div class="col s12 m8">
<div class="contact-card white">
<h4>Send Us a Message</h4>
<form action="{% url 'contact' %}" method="POST">
{% csrf_token %}
<div class="row">
<div class="form-group col s12 m6" style="padding-right:1rem">
<input type="text" class="form-control" class="validate" name="name" placeholder="Your Name">
</div>
<div class="form-group col s12 m6" style="padding-left:1rem">
<input type="email" class="form-control" class="validate" name="email" placeholder="Your Email">
</div>
<!-- <div class="input-field col s12">
<input id="subject" type="text" class="validate" required>
<label for="subject">Subject</label>
</div> -->
<div class="form-group col s12" style="padding-left:1rem">
<input type="text" class="form-control" class="validate" name="subject" placeholder="Subject">
</div>
<div class="form-group col-12" style="padding:1rem">
<textarea name="message" type="text" class="form-control" class="validate" placeholder="Your message"></textarea>
</div>
<div class="form-group col-12">
{% if capchaForm %}
{{ capchaForm }}
{% endif %}
</div>
<div class="col s12">
<!-- <input type="submit" class="btn btn-primary" value="Send"> -->
<button class="btn waves-effect waves-light blue-grey darken-3" type="submit" value="Send">
Send Message
<i class="material-icons right">send</i>
</button>
</div>
</div>
</form>
</div>
</div>
<div class="col s12 m4">
<div class="contact-info">
<h5>Contact Information</h5>
<ul class="collection">
<!-- <li class="collection-item">
<i class="material-icons">location_on</i>
<p>1968 Greensboro Dr<br>Wheaton, IL 60189</p>
</li> -->
<li class="collection-item">
<i class="material-icons">phone</i>
<p>+1 (330) 402-2675</p>
</li>
<li class="collection-item">
<i class="material-icons">email</i>
<p>ryan@aimloperations.com</p>
</li>
</ul>
<!-- <h5>Follow Us</h5>
<div class="social-links">
<a href="#" class="btn-floating blue-grey darken-3">
<i class="material-icons">group</i>
</a>
<a href="#" class="btn-floating blue-grey darken-3">
<i class="material-icons">message</i>
</a>
<a href="#" class="btn-floating blue-grey darken-3">
<i class="material-icons">business</i>
</a>
</div> -->
</div>
</div>
</div>
<!-- Map Section -->
<!-- <div class="row">
<div class="col s12">
<div class="contact-card white">
<h5>Our Location</h5>
<div class="map-container">
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2972.770560296143!2d-88.12337822267253!3d41.83323846821986!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x880e542fbc244bbd%3A0x7aa4cddecbc2cf1f!2s1968%20Greensboro%20Dr%2C%20Wheaton%2C%20IL%2060189!5e0!3m2!1sen!2sus!4v1739220517291!5m2!1sen!2sus"
width="100%"
height="300"
style="border:0;"
allowfullscreen=""
loading="lazy">
</iframe>
</div>
</div>
</div>
</div> -->
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,100 @@
{% extends "base.html" %}
{% load static %}
{% block path %} url({% static 'public/img/bg4.jpeg' %}) {% endblock %}
{% block content %}
<!-- Hero Section -->
<div class="hero-section">
<h1>File Hosting</h1>
<p class="flow-text">Secure, Scalable, and Reliable File Storage with Weekly Backups</p>
</div>
<!-- About File Hosting Section -->
<div class="section white">
<div class="row container">
<h2 class="header">About Our File Hosting Service</h2>
<p class="flow-text">
At AI ML Operations, we provide secure and scalable file hosting solutions tailored to your business needs. Our platform ensures your data is always accessible, protected, and backed up with weekly backups for added peace of mind. Whether you're storing critical business documents, media files, or large datasets, our file hosting service is designed to meet your requirements with reliability and efficiency.
</p>
</div>
</div>
<!-- Features Section -->
<div class="section grey lighten-3">
<div class="row container">
<h2 class="header">What We Offer</h2>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">cloud</i>
<h5>Secure Storage</h5>
<p>Your files are stored securely with advanced encryption protocols.</p>
</div>
</div>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">backup</i>
<h5>Weekly Backups</h5>
<p>Automatic weekly backups to ensure your data is always safe.</p>
</div>
</div>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">storage</i>
<h5>Scalable Solutions</h5>
<p>Easily scale your storage as your business grows.</p>
</div>
</div>
</div>
</div>
<!-- Benefits Section -->
<div class="section white">
<div class="row container">
<h2 class="header">Why Choose Us?</h2>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Data Security">
</div>
<div class="card-content">
<span class="card-title">Data Security</span>
<p>Advanced encryption and access controls to protect your files.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Reliability">
</div>
<div class="card-content">
<span class="card-title">Reliability</span>
<p>99.9% uptime guarantee for uninterrupted access to your files.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Easy Management">
</div>
<div class="card-content">
<span class="card-title">Easy Management</span>
<p>User-friendly interface for seamless file management.</p>
</div>
</div>
</div>
</div>
</div>
<!-- Call to Action Section -->
<div class="section blue-grey darken-3 white-text">
<div class="row container center">
<h2 class="header">Ready to Secure Your Files?</h2>
<p class="flow-text">Contact us today to get started with our file hosting service.</p>
<a href="{% url 'contact' %}" class="btn-large waves-effect waves-light white blue-grey-text text-darken-3">Get Started</a>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,98 @@
{% extends "base.html" %}
{% load static %}
{% block path %} url({% static 'public/img/bg4.jpeg' %}) {% endblock %}
{% block content %}
<!-- Hero Section -->
<div class="hero-section">
<h1>ML Model Creation</h1>
<p class="flow-text">Tailored Machine Learning Models for Any Problem Set</p>
</div>
<!-- About ML Model Creation Section -->
<div class="section white">
<div class="row container">
<h2 class="header">About ML Model Creation</h2>
<p class="flow-text">
At AI ML Operations, we specialize in creating custom machine learning models to solve complex problems across industries. With extensive expertise in supervised, unsupervised, and reinforcement learning, we design models that deliver accurate, scalable, and actionable insights. Whether you need predictive analytics, pattern recognition, or decision-making systems, we provide end-to-end solutions tailored to your needs.
</p>
</div>
</div>
<!-- Features Section -->
<div class="section grey lighten-3">
<div class="row container">
<h2 class="header">What We Offer</h2>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">supervised_user_circle</i>
<h5>Supervised Learning</h5>
<p>Create models for classification, regression, and prediction tasks.</p>
</div>
</div>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">explore</i>
<h5>Unsupervised Learning</h5>
<p>Discover patterns and insights from unlabeled data.</p>
</div>
</div>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">trending_up</i>
<h5>Reinforcement Learning</h5>
<p>Develop systems that learn and adapt through interaction.</p>
</div>
</div>
</div>
</div>
<!-- Applications Section -->
<div class="section white">
<div class="row container">
<h2 class="header">Applications</h2>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Predictive Analytics">
</div>
<div class="card-content">
<span class="card-title">Predictive Analytics</span>
<p>Forecast trends and outcomes with high accuracy.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Fraud Detection">
</div>
<div class="card-content">
<span class="card-title">Fraud Detection</span>
<p>Identify and prevent fraudulent activities in real-time.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Recommendation Systems">
</div>
<div class="card-content">
<span class="card-title">Recommendation Systems</span>
<p>Personalize user experiences with intelligent recommendations.</p>
</div>
</div>
</div>
</div>
</div>
<!-- Call to Action Section -->
<div class="section blue-grey darken-3 white-text">
<div class="row container center">
<h2 class="header">Ready to Solve Your Problem?</h2>
<p class="flow-text">Contact us today to create your custom ML model.</p>
<a href="{% url 'contact' %}" class="btn-large waves-effect waves-light white blue-grey-text text-darken-3">Get Started</a>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,157 @@
{% extends "base.html" %}
{% block content %}
<!-- Hero Section -->
<div class="hero-section">
<h1>AI ML Operations, LLC</h1>
<br />&nbsp;
<p>Taking AI and ML from concept to Production</p>
</div>
<!-- About Us Section -->
<div class="section grey lighten-3">
<div class="row container">
<h2 class="header">About Us</h2>
<p class="flow-text">
At AI/ML Operations, we are dedicated to delivering production-ready AI and ML solutions that seamlessly integrate into your workflows. With over a decade of experience, we specialize in crafting cutting-edge machine learning models and AI algorithms to tackle the most complex and demanding challenges across various industries.
</p>
</div>
</div>
<!-- Services Section -->
<div class="section white">
<div class="row container">
<h2 class="header">Our Services</h2>
<div class="col s12 m6 l4">
<div class="card blue-grey lighten-5">
<div class="card-content">
<span class="card-title"><a href="{% url 'ai_sensor' %}">AI Sensor Algorithms</a></span>
<p>Develop intelligent algorithms that enhance sensor data processing, enabling real-time insights and decision-making for IoT and industrial applications.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card blue-grey lighten-5">
<div class="card-content">
<span class="card-title"><a href="{% url 'ai_education' %}">AI Education</a></span>
<p>Stay ahead of the AI technology curve with our AI Education classes. Classes are tailored to the audience familiarity with AI. Held in-person or virtual.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card blue-grey lighten-5">
<div class="card-content">
<span class="card-title"><a href="{% url 'bot' %}">Bot Creation</a></span>
<p>Build agentic intelligent bots for workflow automation, customer support, and data collection for enhancing productivity and user experience.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card blue-grey lighten-5">
<div class="card-content">
<span class="card-title"><a href="{% url 'chat' %}">Chat</a></span>
<p>Chat is a closed-source Large Language Model (LLM) designed specifically for small and medium businesses.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card blue-grey lighten-5">
<div class="card-content">
<span class="card-title"><a href="{% url 'computers' %}">Computer Builds</a></span>
<p>Wether you're looking for a server for storage or compute or a workstation computer, we will build your next system for you.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card blue-grey lighten-5">
<div class="card-content">
<span class="card-title"><a href="{% url 'file_hosting' %}">File Hosting</a></span>
<p>Secure and scalable file hosting solutions to store, manage, and share your data with ease and confidence.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card blue-grey lighten-5">
<div class="card-content">
<span class="card-title"><a href="{% url 'ml_model' %}">ML Model Creation</a></span>
<p>Design and deploy custom machine learning models tailored to your business needs, ensuring accuracy, scalability, and performance.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card blue-grey lighten-5">
<div class="card-content">
<span class="card-title"><a href="{% url 'web_design' %}">Web Design and Hosting</a></span>
<p>Create visually stunning and highly functional websites, coupled with reliable hosting solutions to ensure your online presence is always at its best.</p>
</div>
</div>
</div>
</div>
</div>
<!-- Contact Us Section -->
<!-- <div class="section grey lighten-3">
<div class="row container">
<h2 class="header">Contact Us</h2>
<form action="{% url 'contact' %}" method="post">
{% csrf_token %}
<div class="row">
{% if success %}
<div class="alert alert-success alert-dismissible fade show" role="alert">
<span class="alert-text"> We'll be in contact shortly!</span>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endif %}
{% if errors %}
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<span class="alert-text">{{ errors }}</span>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endif %}
<div class="col l6 m6 s12">
<div class="form-group" style="padding-left:1rem">
<input type="email" class="form-control" name="email" placeholder="Your Email">
</div>
</div>
<div class="col l6 m6 s12">
<div class="form-group" style="padding-right:1rem">
<input type="text" class="form-control" name="name" placeholder="Your Name">
</div>
</div>
<div class="col l10 m10 s12">
<div class="form-group" style="padding:1rem">
<textarea name="message" type="text" class="form-control" rows="5" placeholder="Your message"></textarea>
</div>
</div>
<div class="col l2 m2 s12">
<input type="submit" class="btn btn-primary" value="Send">
</div>
<div class="col l12 m12 s12">
<div class="form-group">
{% if capchaForm %}
{{ capchaForm }}
{% endif %}
</div>
</div>
</div>
</div>
</form>
</div>
</div> -->
{% endblock %}

View File

@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Email Template</title>
<!-- Materialize CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css" rel="stylesheet">
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
}
.email-container {
max-width: 600px;
margin: 0 auto;
background-color: #ffffff;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.header {
background-color: #37474f;
color: #ffffff;
padding: 20px;
text-align: center;
}
.content {
padding: 20px;
color: #333333;
}
.footer {
background-color: #333;
padding: 10px;
text-align: center;
font-size: 12px;
color: white;
}
</style>
</head>
<body>
<div class="email-container">
<!-- Header -->
<div class="header">
<h4>{{ title | safe }}</h4>
</div>
<!-- Content -->
<div class="content">
{{ content | safe }}
</div>
<!-- Footer -->
<div class="footer">
<p>© 2025 AI ML Operations, LLC. All rights reserved.</p>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,207 @@
{% extends "base.html" %}
{% load static %}
{% block path %} url({% static 'public/img/bg4.jpeg' %}) {% endblock %}
{% block content %}
<!-- Hero Section -->
<div class="hero-section">
<h1>Web Design & Hosting</h1>
<p class="flow-text">Crafting Beautiful, Functional Websites with Reliable Hosting</p>
</div>
<!-- About Web Design & Hosting Section -->
<div class="section white">
<div class="row container">
<h2 class="header">About Our Web Design & Hosting Service</h2>
<p class="flow-text">
At AI ML Operations, we specialize in creating visually stunning, highly functional websites tailored to your business needs. From design to deployment, we handle every aspect of your online presence. Our reliable hosting solutions ensure your website is always fast, secure, and accessible. Whether you need a simple portfolio site or a complex e-commerce platform, weve got you covered.
</p>
</div>
</div>
<!-- Features Section -->
<div class="section grey lighten-3">
<div class="row container">
<h2 class="header">What We Offer</h2>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">design_services</i>
<h5>Custom Web Design</h5>
<p>Tailored designs that reflect your brand and engage your audience.</p>
</div>
</div>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">dns</i>
<h5>Reliable Hosting</h5>
<p>Fast, secure, and scalable hosting solutions for your website.</p>
</div>
</div>
<div class="col s12 m4">
<div class="icon-block">
<i class="material-icons">settings</i>
<h5>Ongoing Support</h5>
<p>Continuous maintenance and support to keep your site running smoothly.</p>
</div>
</div>
</div>
</div>
<!-- Services Section -->
<div class="section white">
<div class="row container">
<h2 class="header">Our Services</h2>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Custom Web Design">
</div>
<div class="card-content">
<span class="card-title">Custom Web Design</span>
<p>Unique, responsive designs tailored to your brand and audience.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="E-Commerce Solutions">
</div>
<div class="card-content">
<span class="card-title">E-Commerce Solutions</span>
<p>Build and optimize online stores for seamless shopping experiences.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Website Hosting">
</div>
<div class="card-content">
<span class="card-title">Website Hosting</span>
<p>Secure, high-performance hosting with 99.9% uptime guarantee.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="SEO Optimization">
</div>
<div class="card-content">
<span class="card-title">SEO Optimization</span>
<p>Improve your website's visibility and ranking on search engines.</p>
</div>
</div>
</div>
<div class="col s12 m6 l4">
<div class="card">
<div class="card-image">
<img src="https://via.placeholder.com/400x200" alt="Maintenance & Support">
</div>
<div class="card-content">
<span class="card-title">Maintenance & Support</span>
<p>Regular updates, backups, and troubleshooting to keep your site running smoothly.</p>
</div>
</div>
</div>
</div>
</div>
<section class="section grey lighten-4">
<div class="container">
<h3 class="center-align">Web Hosting Plans</h3>
<!-- Pricing toggle -->
<div class="row center-align">
<div class="col s12">
<div class="switch">
<label>
Monthly
<input type="checkbox" id="pricingToggle">
<span class="lever"></span>
Yearly
</label>
</div>
</div>
</div>
<!-- Pricing cards -->
<div class="row">
<!-- Monthly Card -->
<div class="col s12 m6 l6">
<div class="card z-depth-2">
<div class="card-content center-align">
<span class="card-title">Standard Plan</span>
<h4>$<span class="price">10</span></h4>
<p class="grey-text"><span class="billing-period">per month</span></p>
<ul class="collection">
<li class="collection-item"><i class="material-icons left">check_circle</i>Web Hosting</li>
<li class="collection-item"><i class="material-icons left">check_circle</i>Weekly Backups</li>
<li class="collection-item"><i class="material-icons left">check_circle</i>SSL Certificate</li>
<li class="collection-item"><i class="material-icons left">check_circle</i>CAPTCHA Protection</li>
<li class="collection-item"><i class="material-icons left">check_circle</i>Email Notifications</li>
<li class="collection-item"><i class="material-icons left">check_circle</i>Backend Admin Access</li>
</ul>
</div>
<div class="card-action center-align">
<a href="#" class="waves-effect waves-light btn blue">Get Started</a>
</div>
</div>
</div>
<!-- Yearly Card -->
<div class="col s12 m6 l6">
<div class="card z-depth-2 teal lighten-1 white-text">
<div class="card-content center-align">
<span class="card-title">Premium Plan</span>
<h4>$<span class="price">15</span></h4>
<p><span class="billing-period">per month</span></p>
<ul class="collection">
<li class="collection-item teal lighten-1 white-text"><i class="material-icons left">check_circle</i>All Standard Features</li>
<li class="collection-item teal lighten-1 white-text"><i class="material-icons left">analytics</i>Monthly Analytics Reports</li>
<li class="collection-item teal lighten-1 white-text"><i class="material-icons left">speed</i>Site Optimization Reports</li>
<li class="collection-item teal lighten-1 white-text"><i class="material-icons left">email</i>HTML Marketing Emails</li>
<li class="collection-item teal lighten-1 white-text"><i class="material-icons left">star</i>2 Months Free (Yearly)</li>
<li class="collection-item teal lighten-1 white-text"><i class="material-icons left">star</i>Priority Support</li>
</ul>
</div>
<div class="card-action center-align">
<a href="#" class="waves-effect waves-light btn white blue-text">Save 20%</a>
</div>
</div>
</div>
</div>
</div>
</section>
<script>
// Toggle functionality
document.getElementById('pricingToggle').addEventListener('change', function() {
const prices = document.querySelectorAll('.price');
const periods = document.querySelectorAll('.billing-period');
if(this.checked) {
prices[0].textContent = '100';
periods[0].textContent = 'per year';
prices[1].textContent = '150';
periods[1].textContent = 'per year';
} else {
prices[0].textContent = '10';
periods[0].textContent = 'per month';
prices[1].textContent = '15';
periods[1].textContent = 'per month';
}
});
</script>
<!-- Call to Action Section -->
<div class="section blue-grey darken-3 white-text">
<div class="row container center">
<h2 class="header">Ready to Build Your Online Presence?</h2>
<p class="flow-text">Contact us today to get started on your website project.</p>
<a href="{% url 'contact' %}" class="btn-large waves-effect waves-light white blue-grey-text text-darken-3">Get Started</a>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@@ -0,0 +1,17 @@
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="public_index"),
path("chat", views.chat, name="chat"),
path("ai_education", views.ai_education, name="ai_education"),
path("computer", views.computers, name="computers"),
path("web_design", views.web_design, name="web_design"),
path("ai_sensor", views.ai_sensor, name="ai_sensor"),
path("file_hosting", views.file_hosting, name="file_hosting"),
path("bot_creation", views.bot, name="bot"),
path("ml_model", views.ml_model, name="ml_model"),
path("contact", views.contact, name="contact"),
path("preview_email/<int:pk>/", views.preview_email, name="preview_email")
]

View File

@@ -0,0 +1,104 @@
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse
from .models import Contact, EmailMessage
from django.template.loader import get_template
from django.core.mail import EmailMultiAlternatives
from django.conf import settings
from django.core.mail import send_mail
from .forms import FormWithCaptcha
from django.contrib.auth.decorators import login_required
def send_contact_email(email, subject, message):
subject = "New Contact Request for AI ML Operations, LLC"
from_email = email
to="ryan@aimloperations.com"
d = {"subject": subject, "message": message, "email": email}
html_content = get_template(r'emails/contact_email.html').render(d)
text_content = get_template(r'emails/contact_email.txt').render(d)
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
msg.attach_alternative(html_content, "text/html")
msg.send(fail_silently=True)
# Create your views here.
def index(request):
return render(request, "public/new_index.html", {})
def chat(request):
return render(request, "public/chat.html", {})
def ai_education(request):
return render(request, "public/ai_education.html", {})
def computers(request):
return render(request, "public/computers.html", {})
def web_design(request):
return render(request, "public/web_design.html", {})
def ai_sensor(request):
return render(request, "public/ai_sensor.html", {})
def file_hosting(request):
return render(request, "public/file_hosting.html", {})
def bot(request):
return render(request, "public/bot.html", {})
def ml_model(request):
return render(request, "public/ml_model.html", {})
@login_required
def preview_email(request, pk):
email_instance = get_object_or_404(EmailMessage, pk=pk)
context = {
"title":email_instance.subject,
"content":email_instance.body
}
return render(
request, 'public/preview_email.html', context
)
def contact(request):
errors = ''
if request.method == 'POST':
name = request.POST.get('name')
email = request.POST.get('email')
message = request.POST.get('message', "")
subject = request.POST.get('subject', "")
capchaForm = FormWithCaptcha(request.POST)
if len(name) > 0 and len(email) > 0 and len(subject) > 0:
if settings.DEBUG or capchaForm.is_valid():
# then we are good
c = Contact(name=name, email=email, blurb=message, subject=subject)
c.save()
# send the email.
try:
send_contact_email(email, subject, message)
except Exception as e:
print(f'Error sending the email {e}')
print('Contact Request:')
print(f'From: {name}')
print(f'Message: {message}')
return render(request, "public/contact.html", {'success':True, 'capchaForm': FormWithCaptcha()})
else:
return render(request, "public/contact.html", {'errors': "There was an error submitting. Try again", 'capchaForm': capchaForm})
else:
if len(name) == 0 and len(email) == 0:
errors = 'Both name and email are required'
elif len(email) == 0:
errors = 'Email is required'
elif len(name) == 0:
errors = 'Name is required'
# we need to show an error
return render(request, "public/contact.html", {'errors': errors, 'capchaForm': capchaForm})
capcha = None if settings.DEBUG else FormWithCaptcha()
return render(request, "public/contact.html", {'capchaForm': capcha})

View File

@@ -0,0 +1 @@
scp -r ./* westfarn@10.0.0.103:/home/westfarn/company_site_temp/

7
requirements.txt Normal file
View File

@@ -0,0 +1,7 @@
asgiref==3.7.2
Django==5.0
sqlparse==0.4.4
typing_extensions==4.8.0
django-enum
django-recaptcha
django-phonenumber-field[phonenumbers]