Compare commits
4 commits
c23304052a
...
9662f98169
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9662f98169 | ||
|
|
d184b0423e | ||
|
|
2248237c79 | ||
|
|
8c1d12a5c4 |
12 changed files with 358 additions and 123 deletions
36
app.py
36
app.py
|
|
@ -4,7 +4,7 @@ Simple Tablet Lending and Return Management Web Application
|
|||
with SQLite backend
|
||||
"""
|
||||
|
||||
from flask import Flask, render_template, request, redirect, url_for, flash
|
||||
from flask import Flask, render_template, request, redirect, url_for, flash, make_response, session
|
||||
import sqlite3
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
|
@ -25,15 +25,41 @@ app.config['BABEL_TRANSLATION_DIRECTORIES'] = 'translations'
|
|||
|
||||
# Locale selector function
|
||||
def get_locale():
|
||||
# Try to get language from URL parameter
|
||||
lang = request.args.get('lang')
|
||||
# Try to get language from cookie
|
||||
lang = request.cookies.get('language')
|
||||
if lang and lang in app.config['LANGUAGES']:
|
||||
return lang
|
||||
# Try to get from session
|
||||
if hasattr(request, 'session') and 'language' in request.session:
|
||||
return request.session['language']
|
||||
# Try to get from browser preferences
|
||||
return request.accept_languages.best_match(app.config['LANGUAGES'].keys())
|
||||
# Default to Spanish (es) for internal app
|
||||
return 'es'
|
||||
|
||||
|
||||
# Before request handler to set language from URL param and persist to cookie/session
|
||||
@app.before_request
|
||||
def handle_language():
|
||||
lang = request.args.get('lang')
|
||||
if lang and lang in app.config['LANGUAGES']:
|
||||
# Store in session
|
||||
session['language'] = lang
|
||||
# Set cookie for longer persistence (1 year)
|
||||
# Note: We need to use response.set_cookie, but before_request can't modify response
|
||||
# So we'll handle this in a separate route
|
||||
return None
|
||||
|
||||
|
||||
# Language switcher endpoint
|
||||
@app.route('/set_language')
|
||||
def set_language():
|
||||
lang = request.args.get('lang')
|
||||
if lang and lang in app.config['LANGUAGES']:
|
||||
session['language'] = lang
|
||||
# Set cookie
|
||||
resp = make_response(redirect(request.referrer or '/'))
|
||||
resp.set_cookie('language', lang, max_age=31536000) # 1 year
|
||||
return resp
|
||||
return redirect(request.referrer or '/')
|
||||
|
||||
# Initialize Babel with locale selector
|
||||
babel = Babel(app, locale_selector=get_locale)
|
||||
|
|
|
|||
176
docs/CORPORATE_DESIGN.md
Normal file
176
docs/CORPORATE_DESIGN.md
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
# Corporate Design Specifications
|
||||
|
||||
## Overview
|
||||
|
||||
This document defines the corporate design specifications for the Tablet Management System, including color palette, logo usage, and branding guidelines.
|
||||
|
||||
---
|
||||
|
||||
## Color Palette
|
||||
|
||||
### Primary Corporate Colors
|
||||
|
||||
The following three colors constitute the official corporate color palette:
|
||||
|
||||
| Color Name | Hex Code | RGB | Usage |
|
||||
|------------|----------|-----|-------|
|
||||
| **Cobalt Blue** | `#1338BE` | rgb(19, 56, 190) | Primary brand color, headers, navigation, main actions |
|
||||
| **Tiger Orange** | `#FC6A03` | rgb(252, 106, 3) | Accents, highlights, loading indicators, secondary actions |
|
||||
| **Emerald Green** | `#028A0F` | rgb(2, 138, 15) | Success states, positive feedback, confirmation |
|
||||
|
||||
### Color Shades
|
||||
|
||||
Each corporate color has been extended with a full shade range (50-900) for use in Tailwind CSS:
|
||||
|
||||
#### Cobalt Blue Shades
|
||||
- `cobalt-50`: `#f0f5ff` (Lightest)
|
||||
- `cobalt-100`: `#e0eaff`
|
||||
- `cobalt-200`: `#b3c6ff`
|
||||
- `cobalt-300`: `#80a0ff`
|
||||
- `cobalt-400`: `#4d7aff`
|
||||
- **`cobalt-500`: `#1338BE`** (Primary)
|
||||
- `cobalt-600`: `#0f2a9c`
|
||||
- `cobalt-700`: `#0b1f72`
|
||||
- `cobalt-800`: `#081552`
|
||||
- `cobalt-900`: `#060f38` (Darkest)
|
||||
|
||||
#### Tiger Orange Shades
|
||||
- `tiger-50`: `#fff8f0` (Lightest)
|
||||
- `tiger-100`: `#ffe8d6`
|
||||
- `tiger-200`: `#ffccab`
|
||||
- `tiger-300`: `#ffae80`
|
||||
- `tiger-400`: `#ff8c55`
|
||||
- **`tiger-500`: `#FC6A03`** (Primary)
|
||||
- `tiger-600`: `#e05a00`
|
||||
- `tiger-700`: `#b84500`
|
||||
- `tiger-800`: `#8c3300`
|
||||
- `tiger-900`: `#662500` (Darkest)
|
||||
|
||||
#### Emerald Green Shades
|
||||
- `emerald-50`: `#f0fdf4` (Lightest)
|
||||
- `emerald-100`: `#dcfce7`
|
||||
- `emerald-200`: `#bbf7d0`
|
||||
- `emerald-300`: `#86efac`
|
||||
- `emerald-400`: `#4ade80`
|
||||
- **`emerald-500`: `#028A0F`** (Primary)
|
||||
- `emerald-600`: `#006b0c`
|
||||
- `emerald-700`: `#005209`
|
||||
- `emerald-800`: `#003d07`
|
||||
- `emerald-900`: `#002904` (Darkest)
|
||||
|
||||
---
|
||||
|
||||
## Logo Usage
|
||||
|
||||
### Logo File
|
||||
- **File**: `assets/Schamann.png`
|
||||
- **Dimensions**: 175 x 161 pixels
|
||||
- **Format**: PNG with transparency
|
||||
- **Web Path**: `/static/Schamann.png`
|
||||
|
||||
### Display Guidelines
|
||||
- The logo should be displayed at a fixed height of 40px in the header
|
||||
- Use `object-contain` to maintain aspect ratio
|
||||
- The logo should appear to the left of the application title
|
||||
- Do not stretch or distort the logo
|
||||
|
||||
### Implementation
|
||||
```html
|
||||
<img src="/static/Schamann.png" alt="Corporate Logo" class="h-10 w-auto object-contain" style="max-height: 40px; height: 40px !important;">
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Headers and Navigation
|
||||
```html
|
||||
<!-- Header background -->
|
||||
<header class="bg-cobalt-600 text-white shadow-lg">
|
||||
|
||||
<!-- Navigation background -->
|
||||
<nav class="bg-cobalt-600 rounded-lg shadow-md">
|
||||
|
||||
<!-- Navigation hover -->
|
||||
<a class="hover:bg-cobalt-700 transition-colors">
|
||||
```
|
||||
|
||||
### Buttons and Actions
|
||||
```html
|
||||
<!-- Primary button (Cobalt Blue) -->
|
||||
<button class="bg-cobalt-600 hover:bg-cobalt-700 text-white">
|
||||
|
||||
<!-- Secondary button (Tiger Orange) -->
|
||||
<button class="bg-tiger-500 hover:bg-tiger-600 text-white">
|
||||
|
||||
<!-- Success button (Emerald Green) -->
|
||||
<button class="bg-emerald-500 hover:bg-emerald-600 text-white">
|
||||
```
|
||||
|
||||
### Status Indicators
|
||||
```html
|
||||
<!-- Success state -->
|
||||
<div class="bg-emerald-100 text-emerald-800">Success!</div>
|
||||
|
||||
<!-- Warning state -->
|
||||
<div class="bg-tiger-100 text-tiger-800">Warning</div>
|
||||
|
||||
<!-- Info state -->
|
||||
<div class="bg-cobalt-100 text-cobalt-800">Info</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tailwind CSS Configuration
|
||||
|
||||
The corporate colors are configured in the Tailwind CSS configuration within the base template:
|
||||
|
||||
```javascript
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
cobalt: {
|
||||
50: '#f0f5ff',
|
||||
100: '#e0eaff',
|
||||
// ... all shades
|
||||
500: '#1338BE',
|
||||
// ...
|
||||
},
|
||||
tiger: {
|
||||
50: '#fff8f0',
|
||||
// ... all shades
|
||||
500: '#FC6A03',
|
||||
// ...
|
||||
},
|
||||
emerald: {
|
||||
50: '#f0fdf4',
|
||||
// ... all shades
|
||||
500: '#028A0F',
|
||||
// ...
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Color Accessibility
|
||||
|
||||
All corporate colors meet WCAG AA contrast requirements when used appropriately:
|
||||
|
||||
- **Cobalt Blue (#1338BE)**: Use white text for backgrounds
|
||||
- **Tiger Orange (#FC6A03)**: Use white text for backgrounds
|
||||
- **Emerald Green (#028A0F)**: Use white text for backgrounds
|
||||
|
||||
For lighter shades (100-300), use dark text (gray-800 or gray-900).
|
||||
|
||||
---
|
||||
|
||||
## Version History
|
||||
|
||||
| Version | Date | Changes |
|
||||
|---------|------|---------|
|
||||
| 1.0 | 2026-06-20 | Initial corporate design specifications with Cobalt Blue, Tiger Orange, and Emerald Green color palette |
|
||||
BIN
static/Schamann.png
Normal file
BIN
static/Schamann.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
|
|
@ -1,63 +1,63 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Add Non-Loanable Device</h2>
|
||||
<p>Add a device that will be tracked in inventory but cannot be loaned to users (e.g., projectors, monitors, etc.)</p>
|
||||
<h2>{{ _('Add Non-Loanable Device') }}</h2>
|
||||
<p>{{ _('Add a device that will be tracked in inventory but cannot be loaned to users (e.g., projectors, monitors, etc.)') }}</p>
|
||||
|
||||
<form method="POST" action="/add_non_loanable_device">
|
||||
<div class="form-group">
|
||||
<label for="device_type">Device Type:</label>
|
||||
<label for="device_type">{{ _('Device Type') }}:</label>
|
||||
<select id="device_type" name="device_type" required>
|
||||
<option value="">Select device type...</option>
|
||||
<option value="projector">Projector</option>
|
||||
<option value="monitor">Monitor</option>
|
||||
<option value="laptop">Laptop (non-loanable)</option>
|
||||
<option value="printer">Printer</option>
|
||||
<option value="camera">Camera</option>
|
||||
<option value="audio">Audio Equipment</option>
|
||||
<option value="network">Network Equipment</option>
|
||||
<option value="other">Other</option>
|
||||
<option value="">{{ _('Select device type...') }}</option>
|
||||
<option value="projector">{{ _('Projector') }}</option>
|
||||
<option value="monitor">{{ _('Monitor') }}</option>
|
||||
<option value="laptop">{{ _('Laptop (non-loanable)') }}</option>
|
||||
<option value="printer">{{ _('Printer') }}</option>
|
||||
<option value="camera">{{ _('Camera') }}</option>
|
||||
<option value="audio">{{ _('Audio Equipment') }}</option>
|
||||
<option value="network">{{ _('Network Equipment') }}</option>
|
||||
<option value="other">{{ _('Other') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="brand">Brand:</label>
|
||||
<label for="brand">{{ _('Brand') }}:</label>
|
||||
<input type="text" id="brand" name="brand" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="model">Model:</label>
|
||||
<label for="model">{{ _('Model') }}:</label>
|
||||
<input type="text" id="model" name="model" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="serial_number">Serial Number:</label>
|
||||
<label for="serial_number">{{ _('Serial Number') }}:</label>
|
||||
<input type="text" id="serial_number" name="serial_number" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="location">Location:</label>
|
||||
<label for="location">{{ _('Location') }}:</label>
|
||||
<input type="text" id="location" name="location">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="purchase_date">Purchase Date:</label>
|
||||
<label for="purchase_date">{{ _('Purchase Date') }}:</label>
|
||||
<input type="date" id="purchase_date" name="purchase_date">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="purchase_cost">Purchase Cost:</label>
|
||||
<label for="purchase_cost">{{ _('Purchase Cost') }}:</label>
|
||||
<input type="number" id="purchase_cost" name="purchase_cost" step="0.01">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="notes">Notes:</label>
|
||||
<label for="notes">{{ _('Notes') }}:</label>
|
||||
<textarea id="notes" name="notes"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn">Add Device</button>
|
||||
<a href="/non_loanable_devices" class="btn">Cancel</a>
|
||||
<button type="submit" class="btn">{{ _('Add Device') }}</button>
|
||||
<a href="/non_loanable_devices" class="btn">{{ _('Cancel') }}</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,30 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Add New Tablet</h2>
|
||||
<h2>{{ _('Add New Tablet') }}</h2>
|
||||
<form method="POST" action="/add_tablet">
|
||||
<div class="form-group">
|
||||
<label for="brand">Brand:</label>
|
||||
<label for="brand">{{ _('Brand') }}:</label>
|
||||
<input type="text" id="brand" name="brand" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="model">Model:</label>
|
||||
<label for="model">{{ _('Model') }}:</label>
|
||||
<input type="text" id="model" name="model" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="serial_number">Serial Number:</label>
|
||||
<label for="serial_number">{{ _('Serial Number') }}:</label>
|
||||
<input type="text" id="serial_number" name="serial_number" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="notes">Notes:</label>
|
||||
<label for="notes">{{ _('Notes') }}:</label>
|
||||
<textarea id="notes" name="notes"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn">Add Tablet</button>
|
||||
<button type="submit" class="btn">{{ _('Add Tablet') }}</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
|
@ -1,30 +1,30 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Add New User</h2>
|
||||
<h2>{{ _('Add New User') }}</h2>
|
||||
<form method="POST" action="/add_user">
|
||||
<div class="form-group">
|
||||
<label for="name">Name:</label>
|
||||
<label for="name">{{ _('Name') }}:</label>
|
||||
<input type="text" id="name" name="name" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">Email:</label>
|
||||
<label for="email">{{ _('Email') }}:</label>
|
||||
<input type="email" id="email" name="email">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="phone">Phone:</label>
|
||||
<label for="phone">{{ _('Phone') }}:</label>
|
||||
<input type="text" id="phone" name="phone">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="identification">Identification:</label>
|
||||
<label for="identification">{{ _('Identification') }}:</label>
|
||||
<input type="text" id="identification" name="identification" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn">Add User</button>
|
||||
<button type="submit" class="btn">{{ _('Add User') }}</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
height: 20px;
|
||||
border: 3px solid rgba(0,0,0,.3);
|
||||
border-radius: 50%;
|
||||
border-top-color: #10b981;
|
||||
border-top-color: #FC6A03;
|
||||
animation: spin 1s ease-in-out infinite;
|
||||
}
|
||||
@keyframes spin {
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
}
|
||||
</style>
|
||||
|
||||
<!-- Tailwind config for custom colors -->
|
||||
<!-- Tailwind config for custom corporate colors -->
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
|
|
@ -58,6 +58,42 @@
|
|||
700: '#047857',
|
||||
800: '#065f46',
|
||||
900: '#064e3b',
|
||||
},
|
||||
cobalt: {
|
||||
50: '#f0f5ff',
|
||||
100: '#e0eaff',
|
||||
200: '#b3c6ff',
|
||||
300: '#80a0ff',
|
||||
400: '#4d7aff',
|
||||
500: '#1338BE',
|
||||
600: '#0f2a9c',
|
||||
700: '#0b1f72',
|
||||
800: '#081552',
|
||||
900: '#060f38',
|
||||
},
|
||||
tiger: {
|
||||
50: '#fff8f0',
|
||||
100: '#ffe8d6',
|
||||
200: '#ffccab',
|
||||
300: '#ffae80',
|
||||
400: '#ff8c55',
|
||||
500: '#FC6A03',
|
||||
600: '#e05a00',
|
||||
700: '#b84500',
|
||||
800: '#8c3300',
|
||||
900: '#662500',
|
||||
},
|
||||
emerald: {
|
||||
50: '#f0fdf4',
|
||||
100: '#dcfce7',
|
||||
200: '#bbf7d0',
|
||||
300: '#86efac',
|
||||
400: '#4ade80',
|
||||
500: '#028A0F',
|
||||
600: '#006b0c',
|
||||
700: '#005209',
|
||||
800: '#003d07',
|
||||
900: '#002904',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -72,15 +108,12 @@
|
|||
<!-- Container -->
|
||||
<div class="min-h-screen">
|
||||
<!-- Header -->
|
||||
<header class="bg-primary-600 text-white shadow-lg">
|
||||
<header class="bg-cobalt-600 text-white shadow-lg">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex items-center justify-between h-16">
|
||||
<!-- Logo / Title -->
|
||||
<div class="flex items-center gap-3">
|
||||
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"></path>
|
||||
</svg>
|
||||
<img src="/static/Schamann.png" alt="Corporate Logo" class="h-10 w-auto object-contain" style="max-height: 40px; height: 40px !important;">
|
||||
<h1 class="text-xl font-bold">{{ _('Tablet Management System') }}</h1>
|
||||
</div>
|
||||
|
||||
|
|
@ -89,7 +122,7 @@
|
|||
<span class="text-sm opacity-80">{{ _('Language') }}:</span>
|
||||
{% for lang_code, lang_name in config['LANGUAGES'].items() %}
|
||||
<a
|
||||
href="?lang={{ lang_code }}"
|
||||
href="{{ url_for('set_language', lang=lang_code) }}"
|
||||
class="px-2 py-1 text-sm rounded hover:bg-white/20 transition-colors
|
||||
{% if language == lang_code %}bg-white/30 font-medium{% endif %}"
|
||||
>
|
||||
|
|
@ -134,39 +167,39 @@
|
|||
{% endwith %}
|
||||
|
||||
<!-- Navigation -->
|
||||
<nav class="bg-primary-600 rounded-lg shadow-md mb-6" aria-label="Main navigation">
|
||||
<nav class="bg-cobalt-600 rounded-lg shadow-md mb-6" aria-label="Main navigation">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex flex-wrap justify-center sm:justify-start gap-1 sm:gap-2 py-3">
|
||||
<a href="/"
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-primary-700 transition-colors whitespace-nowrap">
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-cobalt-700 transition-colors whitespace-nowrap">
|
||||
{{ _('Home') }}
|
||||
</a>
|
||||
<a href="/add_tablet"
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-primary-700 transition-colors whitespace-nowrap">
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-cobalt-700 transition-colors whitespace-nowrap">
|
||||
{{ _('Add Tablet') }}
|
||||
</a>
|
||||
<a href="/add_user"
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-primary-700 transition-colors whitespace-nowrap">
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-cobalt-700 transition-colors whitespace-nowrap">
|
||||
{{ _('Add User') }}
|
||||
</a>
|
||||
<a href="/loan_tablet"
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-primary-700 transition-colors whitespace-nowrap">
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-cobalt-700 transition-colors whitespace-nowrap">
|
||||
{{ _('Loan Tablet') }}
|
||||
</a>
|
||||
<a href="/history"
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-primary-700 transition-colors whitespace-nowrap">
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-cobalt-700 transition-colors whitespace-nowrap">
|
||||
{{ _('History') }}
|
||||
</a>
|
||||
<a href="/user_loans"
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-primary-700 transition-colors whitespace-nowrap">
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-cobalt-700 transition-colors whitespace-nowrap">
|
||||
{{ _('User Loans') }}
|
||||
</a>
|
||||
<a href="/non_loanable_devices"
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-primary-700 transition-colors whitespace-nowrap">
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-cobalt-700 transition-colors whitespace-nowrap">
|
||||
{{ _('Non-Loanable Devices') }}
|
||||
</a>
|
||||
<a href="/project_management"
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-primary-700 transition-colors whitespace-nowrap">
|
||||
class="px-3 py-2 text-sm sm:text-base text-white rounded hover:bg-cobalt-700 transition-colors whitespace-nowrap">
|
||||
{{ _('Project Management') }}
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,71 +1,71 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Edit Non-Loanable Device</h2>
|
||||
<h2>{{ _('Edit Non-Loanable Device') }}</h2>
|
||||
|
||||
<form method="POST" action="/edit_non_loanable_device/{{ device.id }}">
|
||||
<div class="form-group">
|
||||
<label for="device_type">Device Type:</label>
|
||||
<label for="device_type">{{ _('Device Type') }}:</label>
|
||||
<select id="device_type" name="device_type" required>
|
||||
<option value="projector" {% if device.device_type == 'projector' %}selected{% endif %}>Projector</option>
|
||||
<option value="monitor" {% if device.device_type == 'monitor' %}selected{% endif %}>Monitor</option>
|
||||
<option value="laptop" {% if device.device_type == 'laptop' %}selected{% endif %}>Laptop (non-loanable)</option>
|
||||
<option value="printer" {% if device.device_type == 'printer' %}selected{% endif %}>Printer</option>
|
||||
<option value="camera" {% if device.device_type == 'camera' %}selected{% endif %}>Camera</option>
|
||||
<option value="audio" {% if device.device_type == 'audio' %}selected{% endif %}>Audio Equipment</option>
|
||||
<option value="network" {% if device.device_type == 'network' %}selected{% endif %}>Network Equipment</option>
|
||||
<option value="other" {% if device.device_type == 'other' %}selected{% endif %}>Other</option>
|
||||
<option value="projector" {% if device.device_type == 'projector' %}selected{% endif %}>{{ _('Projector') }}</option>
|
||||
<option value="monitor" {% if device.device_type == 'monitor' %}selected{% endif %}>{{ _('Monitor') }}</option>
|
||||
<option value="laptop" {% if device.device_type == 'laptop' %}selected{% endif %}>{{ _('Laptop (non-loanable)') }}</option>
|
||||
<option value="printer" {% if device.device_type == 'printer' %}selected{% endif %}>{{ _('Printer') }}</option>
|
||||
<option value="camera" {% if device.device_type == 'camera' %}selected{% endif %}>{{ _('Camera') }}</option>
|
||||
<option value="audio" {% if device.device_type == 'audio' %}selected{% endif %}>{{ _('Audio Equipment') }}</option>
|
||||
<option value="network" {% if device.device_type == 'network' %}selected{% endif %}>{{ _('Network Equipment') }}</option>
|
||||
<option value="other" {% if device.device_type == 'other' %}selected{% endif %}>{{ _('Other') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="brand">Brand:</label>
|
||||
<label for="brand">{{ _('Brand') }}:</label>
|
||||
<input type="text" id="brand" name="brand" value="{{ device.brand }}" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="model">Model:</label>
|
||||
<label for="model">{{ _('Model') }}:</label>
|
||||
<input type="text" id="model" name="model" value="{{ device.model }}" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="serial_number">Serial Number:</label>
|
||||
<label for="serial_number">{{ _('Serial Number') }}:</label>
|
||||
<input type="text" id="serial_number" name="serial_number" value="{{ device.serial_number }}" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="location">Location:</label>
|
||||
<label for="location">{{ _('Location') }}:</label>
|
||||
<input type="text" id="location" name="location" value="{{ device.location or '' }}">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="status">Status:</label>
|
||||
<label for="status">{{ _('Status') }}:</label>
|
||||
<select id="status" name="status" required>
|
||||
<option value="available" {% if device.status == 'available' %}selected{% endif %}>Available</option>
|
||||
<option value="in_use" {% if device.status == 'in_use' %}selected{% endif %}>In Use</option>
|
||||
<option value="maintenance" {% if device.status == 'maintenance' %}selected{% endif %}>Maintenance</option>
|
||||
<option value="retired" {% if device.status == 'retired' %}selected{% endif %}>Retired</option>
|
||||
<option value="available" {% if device.status == 'available' %}selected{% endif %}>{{ _('Available') }}</option>
|
||||
<option value="in_use" {% if device.status == 'in_use' %}selected{% endif %}>{{ _('In Use') }}</option>
|
||||
<option value="maintenance" {% if device.status == 'maintenance' %}selected{% endif %}>{{ _('Maintenance') }}</option>
|
||||
<option value="retired" {% if device.status == 'retired' %}selected{% endif %}>{{ _('Retired') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="purchase_date">Purchase Date:</label>
|
||||
<label for="purchase_date">{{ _('Purchase Date') }}:</label>
|
||||
<input type="date" id="purchase_date" name="purchase_date" value="{{ device.purchase_date or '' }}">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="purchase_cost">Purchase Cost:</label>
|
||||
<label for="purchase_cost">{{ _('Purchase Cost') }}:</label>
|
||||
<input type="number" id="purchase_cost" name="purchase_cost" step="0.01" value="{{ device.purchase_cost or '' }}">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="notes">Notes:</label>
|
||||
<label for="notes">{{ _('Notes') }}:</label>
|
||||
<textarea id="notes" name="notes">{{ device.notes or '' }}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn">Update Device</button>
|
||||
<a href="/non_loanable_devices" class="btn">Cancel</a>
|
||||
<button type="submit" class="btn">{{ _('Update Device') }}</button>
|
||||
<a href="/non_loanable_devices" class="btn">{{ _('Cancel') }}</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -2,18 +2,18 @@
|
|||
|
||||
{% block content %}
|
||||
<div class="section">
|
||||
<h2>Loan History</h2>
|
||||
<h2>{{ _('Loan History') }}</h2>
|
||||
{% if loans %}
|
||||
<div class="table-container">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Tablet</th>
|
||||
<th>Serial Number</th>
|
||||
<th>Borrower</th>
|
||||
<th>Loan Date</th>
|
||||
<th>Return Date</th>
|
||||
<th>Status</th>
|
||||
<th>{{ _('Tablet') }}</th>
|
||||
<th>{{ _('Serial Number') }}</th>
|
||||
<th>{{ _('Borrower') }}</th>
|
||||
<th>{{ _('Loan Date') }}</th>
|
||||
<th>{{ _('Return Date') }}</th>
|
||||
<th>{{ _('Status') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p>No loan history available.</p>
|
||||
<p>{{ _('No loan history available.') }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Loan Tablet</h2>
|
||||
<h2>{{ _('Loan Tablet') }}</h2>
|
||||
<form method="POST" action="/loan_tablet">
|
||||
<!-- Tablet Selection with Search -->
|
||||
<div class="form-group">
|
||||
<label for="tablet_id">Tablet:</label>
|
||||
<label for="tablet_id">{{ _('Tablet') }}:</label>
|
||||
<input type="text" id="tablet_search" class="search-input"
|
||||
placeholder="Search tablets (brand, model, or serial)..."
|
||||
placeholder="{{ _('Search tablets (brand, model, or serial)...') }}"
|
||||
onkeyup="filterDropdown('tablet_search', 'tablet_id')">
|
||||
<select id="tablet_id" name="tablet_id" required size="5">
|
||||
<option value="">Select a tablet</option>
|
||||
<option value="">{{ _('Select a tablet') }}</option>
|
||||
{% for tablet in available_tablets %}
|
||||
<option value="{{ tablet.id }}"
|
||||
data-search="{{ tablet.brand|lower }} {{ tablet.model|lower }} {{ tablet.serial_number|lower }}">
|
||||
|
|
@ -22,12 +22,12 @@
|
|||
|
||||
<!-- User Selection with Search -->
|
||||
<div class="form-group">
|
||||
<label for="user_id">User:</label>
|
||||
<label for="user_id">{{ _('User') }}:</label>
|
||||
<input type="text" id="user_search" class="search-input"
|
||||
placeholder="Search users (name or ID)..."
|
||||
placeholder="{{ _('Search users (name or ID)...') }}"
|
||||
onkeyup="filterDropdown('user_search', 'user_id')">
|
||||
<select id="user_id" name="user_id" required size="5">
|
||||
<option value="">Select a user</option>
|
||||
<option value="">{{ _('Select a user') }}</option>
|
||||
{% for user in users %}
|
||||
<option value="{{ user.id }}"
|
||||
data-search="{{ user.name|lower }} {{ user.identification|lower }}">
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn">Loan Tablet</button>
|
||||
<button type="submit" class="btn">{{ _('Loan Tablet') }}</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,22 +2,22 @@
|
|||
|
||||
{% block content %}
|
||||
<div class="section">
|
||||
<h2>Non-Loanable Devices Inventory</h2>
|
||||
<p>These devices are tracked in inventory but cannot be loaned to users.</p>
|
||||
<a href="/add_non_loanable_device" class="btn">Add Non-Loanable Device</a>
|
||||
<h2>{{ _('Non-Loanable Devices Inventory') }}</h2>
|
||||
<p>{{ _('These devices are tracked in inventory but cannot be loaned to users.') }}</p>
|
||||
<a href="/add_non_loanable_device" class="btn">{{ _('Add Non-Loanable Device') }}</a>
|
||||
|
||||
{% if devices %}
|
||||
<div class="table-container">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Brand</th>
|
||||
<th>Model</th>
|
||||
<th>Serial Number</th>
|
||||
<th>Location</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
<th>{{ _('Type') }}</th>
|
||||
<th>{{ _('Brand') }}</th>
|
||||
<th>{{ _('Model') }}</th>
|
||||
<th>{{ _('Serial Number') }}</th>
|
||||
<th>{{ _('Location') }}</th>
|
||||
<th>{{ _('Status') }}</th>
|
||||
<th>{{ _('Actions') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
@ -30,8 +30,8 @@
|
|||
<td>{{ device.location or '-' }}</td>
|
||||
<td>{{ device.status }}</td>
|
||||
<td>
|
||||
<a href="/edit_non_loanable_device/{{ device.id }}" class="btn">Edit</a>
|
||||
<a href="/delete_non_loanable_device/{{ device.id }}" class="btn btn-danger" onclick="return confirm('Are you sure you want to delete this device?')">Delete</a>
|
||||
<a href="/edit_non_loanable_device/{{ device.id }}" class="btn">{{ _('Edit') }}</a>
|
||||
<a href="/delete_non_loanable_device/{{ device.id }}" class="btn btn-danger" onclick="return confirm('{{ _("Are you sure you want to delete this device?") }}')">{{ _('Delete') }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p>No non-loanable devices registered.</p>
|
||||
<p>{{ _('No non-loanable devices registered.') }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,25 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Project Management - Development Notes</h2>
|
||||
<h2>{{ _('Project Management - Development Notes') }}</h2>
|
||||
|
||||
<div class="project-management-container">
|
||||
<div class="editor-section">
|
||||
<div class="editor-controls">
|
||||
<button onclick="saveNotes()" class="btn">Save Notes</button>
|
||||
<button onclick="loadNotes()" class="btn">Reload</button>
|
||||
<button onclick="saveNotes()" class="btn">{{ _('Save Notes') }}</button>
|
||||
<button onclick="loadNotes()" class="btn">{{ _('Reload') }}</button>
|
||||
<span id="status" style="margin-left: 15px; font-style: italic;"></span>
|
||||
</div>
|
||||
|
||||
<div class="editor-row">
|
||||
<div class="editor-col">
|
||||
<h3>Editor</h3>
|
||||
<h3>{{ _('Editor') }}</h3>
|
||||
<textarea id="markdown-editor" class="markdown-editor"
|
||||
placeholder="Write your markdown notes here..."></textarea>
|
||||
placeholder="{{ _('Write your markdown notes here...') }}"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="editor-col">
|
||||
<h3>Preview</h3>
|
||||
<h3>{{ _('Preview') }}</h3>
|
||||
<div id="markdown-preview" class="markdown-preview"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -54,13 +54,13 @@
|
|||
.then(content => {
|
||||
document.getElementById('markdown-editor').value = content;
|
||||
document.getElementById('markdown-preview').innerHTML = marked.parse(content);
|
||||
document.getElementById('status').textContent = 'Loaded successfully';
|
||||
document.getElementById('status').textContent = '{{ _("Loaded successfully") }}';
|
||||
setTimeout(() => {
|
||||
document.getElementById('status').textContent = '';
|
||||
}, 2000);
|
||||
})
|
||||
.catch(error => {
|
||||
document.getElementById('status').textContent = 'Using default content';
|
||||
document.getElementById('status').textContent = '{{ _("Using default content") }}';
|
||||
setTimeout(() => {
|
||||
document.getElementById('status').textContent = '';
|
||||
}, 2000);
|
||||
|
|
@ -80,10 +80,10 @@
|
|||
})
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
statusEl.textContent = 'Saved successfully!';
|
||||
statusEl.textContent = '{{ _("Saved successfully!") }}';
|
||||
statusEl.style.color = '#4CAF50';
|
||||
} else {
|
||||
statusEl.textContent = 'Error saving';
|
||||
statusEl.textContent = '{{ _("Error saving") }}';
|
||||
statusEl.style.color = '#f44336';
|
||||
}
|
||||
setTimeout(() => {
|
||||
|
|
@ -92,7 +92,7 @@
|
|||
}, 2000);
|
||||
})
|
||||
.catch(error => {
|
||||
statusEl.textContent = 'Error: ' + error.message;
|
||||
statusEl.textContent = '{{ _("Error") }}: ' + error.message;
|
||||
statusEl.style.color = '#f44336';
|
||||
setTimeout(() => {
|
||||
statusEl.textContent = '';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue