Compare commits

..

4 commits

Author SHA1 Message Date
ijuanes
9662f98169 Revert "docs: add project history narrative in Spanish for Ivan"\n\nThis commit has been undone by moving the file to ~/tmp/ 2026-06-20 15:37:25 +01:00
ijuanes
d184b0423e docs: add project history narrative in Spanish for Ivan
- Complete project narrative from CLI to web application
- Covers all milestones: i18n, responsive design, corporate identity
- Includes providers, technologies, and lessons learned
- Written in Spanish for Ivan
- Omits sensitive information (API keys, credentials)
2026-06-20 15:00:24 +01:00
ijuanes
2248237c79 fix(i18n): enable translations in all templates and implement cookie-based language persistence
- Add _() translation function to add_tablet.html, add_user.html, loan_tablet.html
- Add _() translation function to add_non_loanable_device.html, edit_non_loanable_device.html
- Add _() translation function to history.html, non_loanable_devices.html, project_management.html
- Update app.py to use cookie-based language persistence with 1-year expiry
- Add /set_language endpoint to handle language switching with cookie + session
- Update language switcher in base.html to use new endpoint
- Set Spanish (es) as default language for internal app
- Import make_response and session from Flask
2026-06-20 13:14:41 +01:00
ijuanes
8c1d12a5c4 feat(ui): add corporate logo and update colors to Cobalt Blue, Tiger Orange, Emerald Green
- Add Schamann.png logo to static/ directory
- Update base.html header with logo (force scaled to 40px)
- Replace primary color with corporate color palette:
  - Cobalt Blue (#1338BE) for headers and navigation
  - Tiger Orange (#FC6A03) for accents and loading indicators
  - Emerald Green (#028A0F) for success states
- Add full shade ranges (50-900) for all three colors in Tailwind config
- Create docs/CORPORATE_DESIGN.md with color specifications and usage guidelines
2026-06-20 12:40:00 +01:00
12 changed files with 358 additions and 123 deletions

36
app.py
View file

@ -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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -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 %}

View file

@ -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 %}
{% endblock %}

View file

@ -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 %}
{% endblock %}

View file

@ -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>

View file

@ -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 %}

View file

@ -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 %}
{% endblock %}

View file

@ -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>
@ -75,4 +75,4 @@
overflow-y: auto;
}
</style>
{% endblock %}
{% endblock %}

View file

@ -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 %}

View file

@ -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 = '';