invoice table added

This commit is contained in:
Isaak Buslovich 2024-01-29 19:06:15 +01:00
parent bbf4f9ed15
commit e9b2b71226
6 changed files with 182 additions and 46 deletions

2
app/data/invoices.csv Normal file
View File

@ -0,0 +1,2 @@
Rechnungsnummer;Email;Anrede
RE357891;isaak.buslovich@trocknerheld.de;Isaak Trocknerheld
1 Rechnungsnummer Email Anrede
2 RE357891 isaak.buslovich@trocknerheld.de Isaak Trocknerheld

View File

@ -1,8 +1,30 @@
from flask import render_template, redirect, url_for, current_app
from flask import render_template, redirect, url_for, current_app, render_template_string, request
import os
import csv
from app import app, htmx
def read_invoices_from_csv(csv_file_path):
try:
with open(csv_file_path, mode='r', encoding='utf-8') as file:
return list(csv.DictReader(file, delimiter=';'))
except FileNotFoundError:
current_app.logger.error(f"CSV file not found at {csv_file_path}")
except csv.Error as e:
current_app.logger.error(f"Error reading CSV file: {e}")
return []
@app.route('/load-invoices')
def load_invoices():
csv_file_path = os.path.join(current_app.root_path, 'data', 'invoices.csv')
invoices = read_invoices_from_csv(csv_file_path)
if not invoices:
return "No invoice data available", 500
return render_template('partials/invoice_table.html', invoices=invoices)
def render_htmx_or_full(template_partial, template_full):
try:
if htmx:
@ -10,7 +32,6 @@ def render_htmx_or_full(template_partial, template_full):
return render_template(template_full)
except Exception as e:
current_app.logger.error(f"Error rendering template: {e}")
# Optionally, you can return a custom error page here
return "An error occurred", 500
@ -24,12 +45,42 @@ def buchhaltung():
return render_htmx_or_full('partials/buchhaltung.html', 'index.html')
@app.route('/add-invoice', methods=['POST'])
def add_invoice():
csv_file_path = os.path.join(current_app.root_path, 'data', 'invoices.csv')
new_invoice = {
'Rechnungsnummer': request.form['rechnungsnummer'],
'Email': request.form['email'],
'Anrede': request.form['anrede']
}
try:
# Read the existing data
with open(csv_file_path, 'r', newline='', encoding='utf-8') as csvfile:
reader = csv.DictReader(csvfile, delimiter=';')
fieldnames = reader.fieldnames
existing_data = list(reader)
# Add the new invoice at the beginning of the data
existing_data.insert(0, new_invoice)
# Write the updated data back to the file
with open(csv_file_path, 'w', newline='', encoding='utf-8') as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=fieldnames, delimiter=';')
writer.writeheader()
writer.writerows(existing_data)
return redirect(url_for('buchhaltung'))
except Exception as e:
current_app.logger.error(f"Error updating CSV file: {e}")
return "An error occurred while adding the invoice", 500
@app.route('/flottenmanagement')
def flottenmanagement():
return render_htmx_or_full('partials/flottenmanagement.html', 'index.html')
# Additional debug route to check the file structure
@app.route('/debug/templates')
def debug_templates():
template_dir = os.path.join(current_app.root_path, 'templates')

View File

@ -1,12 +1,26 @@
/* Import Google Fonts */
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
/* Root and Variable Definitions */
:root {
--sidebar-width-collapsed: 60px;
--sidebar-width-expanded: 280px;
--max-container-width: 1200px;
--primary-color: #007BFF;
--primary-color-hover: #0066cc;
--light-grey: #F8F9FA;
--dark-grey: #343A40;
--white: #FFFFFF;
--box-shadow-color: rgba(0, 0, 0, 0.1);
--box-shadow-hover-color: rgba(0, 0, 0, 0.15);
}
/* Body and Global Styles */
body {
font-family: 'Roboto', sans-serif;
margin: 0;
padding: 0;
background: #F8F9FA;
background: var(--light-grey);
display: flex;
height: 100vh;
overflow: hidden;
@ -16,67 +30,73 @@ body {
.sidebar {
display: flex;
flex-direction: column;
background: #FFFFFF;
width: 60px; /* Collapsed width */
background: var(--white);
width: var(--sidebar-width-collapsed);
height: 100%;
transition: width 0.3s ease; /* Smooth transition for expanding */
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
transition: width 0.3s ease;
box-shadow: 2px 0 5px var(--box-shadow-color);
overflow: hidden;
z-index: 20;
}
.sidebar:hover, .sidebar.sidebar-expanded {
width: 280px;
width: var(--sidebar-width-expanded);
}
.menu-item {
display: flex;
align-items: center;
padding: 15px 20px;
color: #343A40;
color: var(--dark-grey);
font-size: 16px;
transition: background-color 0.3s, padding-left 0.3s;
cursor: pointer;
overflow: hidden; /* Hide overflow when sidebar is collapsed */
overflow: hidden;
}
.menu-item:hover {
background-color: #007BFF;
color: #FFFFFF;
background-color: var(--primary-color);
color: var(--white);
}
.menu-icon {
margin-right: 10px;
transition: transform 0.3s ease; /* Smooth icon transition */
transition: transform 0.3s ease;
}
.sidebar:hover .menu-icon, .sidebar.sidebar-expanded .menu-icon {
transform: rotate(360deg); /* Rotate icon on hover */
transform: rotate(360deg);
}
.menu-label {
white-space: nowrap;
overflow: hidden;
transition: opacity 0.3s ease, width 0.3s ease;
display: none; /* Hide labels initially */
display: none;
}
.sidebar:hover .menu-label, .sidebar.sidebar-expanded .menu-label {
display: inline; /* Show labels when sidebar is expanded */
display: inline;
}
/* Adjust sidebar for touch devices (no hover) */
@media (hover: none) {
.sidebar:hover .menu-label {
display: none;
@media (min-width: 1200px) {
.container {
max-width: var(--max-container-width);
margin: auto;
padding: 20px 40px;
}
.card-grid {
grid-template-columns: repeat(3, 1fr);
gap: 30px;
}
}
/* Responsive Design */
/* Responsive Design for Smaller Screens */
@media (max-width: 768px) {
.sidebar {
position: fixed;
width: 60px;
width: var(--sidebar-width-collapsed);
}
.sidebar-expanded {
@ -84,46 +104,68 @@ body {
}
.container {
margin-left: 60px;
width: calc(100% - 60px);
margin-left: var(--sidebar-width-collapsed);
width: calc(100% - var(--sidebar-width-collapsed));
}
.sidebar-expanded + .container {
margin-left: 200px;
width: calc(100% - 200px);
}
.card-grid {
grid-template-columns: 1fr;
}
}
/* Main Content Styles */
.container {
margin-left: 60px;
margin-left: var(--sidebar-width-collapsed);
transition: margin-left 0.3s ease;
padding: 20px;
width: calc(100% - 60px);
width: calc(100% - var(--sidebar-width-collapsed));
overflow-y: auto;
}
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
grid-template-columns: 1fr;
gap: 20px;
}
.card {
background-color: white;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
background-color: var(--white);
box-shadow: 0 4px 8px var(--box-shadow-color);
border-radius: 10px;
overflow: hidden;
transition: transform 0.3s ease, box-shadow 0.3s ease;
transition: transform 0.2s ease, box-shadow 0.2s ease;
display: flex;
flex-direction: column;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
transform: translateY(-2px);
box-shadow: 0 5px 10px var(--box-shadow-hover-color);
}
.card-container {
padding: 20px;
display: flex;
flex-direction: column;
flex-grow: 1;
}
/* Table Styles */
.card table {
width: 100%;
border-collapse: collapse;
table-layout: fixed;
}
.card th, .card td {
border: 1px solid #ddd;
padding: 8px;
word-wrap: break-word;
}
/* Form and Button Styles */
@ -136,18 +178,17 @@ input, .button {
}
.button {
background-color: #007BFF;
color: white;
background-color: var(--primary-color);
color: var(--white);
border: none;
cursor: pointer;
transition: background-color 0.3s;
}
.button:hover {
background-color: #003875;
background-color: var(--primary-color-hover);
}
/* Login Overlay Styles */
.login-overlay {
position: fixed;
top: 0;
@ -168,7 +209,6 @@ input, .button {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}
/* Tabbed Interface Styles */
.tab-group {
list-style: none;
padding: 0;
@ -201,7 +241,6 @@ input, .button {
border-bottom: 2px solid white;
}
/* Tab Content */
.tab-content {
background: #fff;
padding: 20px;

View File

@ -1,9 +1,9 @@
<!DOCTYPE html>
<html lang="en">
<html lang="de">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>Enhanced Web App with Sidebar</title>
<title>Tocknerheld-Dashboard</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="/static/css/style.css" rel="stylesheet" type="text/css">
<script src="https://unpkg.com/htmx.org"></script>
@ -87,7 +87,7 @@
<section id="main-content">
<!-- Initial content or instruction for the user -->
<h1>Tocknerheld-Dashboard</h1>
<p>Select a menu item to view content.</p>
<p>Bitte wähle einen Menüpunkt, um in den entsprechenden Bereich zu springen.</p>
</section>
</div>
<script src="/static/js/script.js"></script>

View File

@ -1,14 +1,36 @@
<div class="card-grid">
<div class="card">
<div class="card-container">
<h3 class="card-title">Card Title 1</h3>
<p class="card-text">This is a description for card 1.</p>
<h3 class="card-title">Rechnung hinzufügen</h3>
<form method="post" hx-post="/add-invoice" hx-target="#main-content" hx-swap="outerHTML">
<div class="form-group">
<label for="rechnungsnummer">Rechnungsnummer:</label>
<input id="rechnungsnummer" name="rechnungsnummer" type="text" required>
</div>
<div class="form-group">
<label for="email">Email:</label>
<input id="email" name="email" type="email" required>
</div>
<div class="form-group">
<label for="anrede">Anrede:</label>
<input id="anrede" name="anrede" type="text" required>
</div>
<button class="button" type="submit">Hinzufügen</button>
</form>
</div>
</div>
<div class="card">
<div class="card-container">
<h3 class="card-title">Card Title 2</h3>
<p class="card-text">This is a description for card 2.</p>
<h3 class="card-title">Versendete Rechnungen</h3>
<p class="card-text">Tabelle aller versendeter Rechnungen inklusive E-Mail und Anrede</p>
<p class="card-text">
<!-- Table for invoices -->
<table>
<tbody hx-get="/load-invoices" hx-trigger="load">
<!-- Dynamically loaded rows will appear here -->
</tbody>
</table>
</p>
</div>
</div>
</div>

View File

@ -0,0 +1,22 @@
{% if invoices %}
<table>
<thead>
<tr>
<th>Rechnungsnummer</th>
<th>Email</th>
<th>Anrede</th>
</tr>
</thead>
<tbody>
{% for invoice in invoices %}
<tr>
<td>{{ invoice['Rechnungsnummer'] }}</td>
<td>{{ invoice['Email'] }}</td>
<td>{{ invoice['Anrede'] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>No invoices available.</p>
{% endif %}