update shop
This commit is contained in:
@@ -22,10 +22,12 @@ RUN mkdir -p /app/instance /app/assets
|
||||
# Default port
|
||||
ENV FLET_PORT=8080
|
||||
|
||||
EXPOSE 8080
|
||||
# Copy the entrypoint script and make it executable
|
||||
COPY entrypoint.sh .
|
||||
RUN chmod +x entrypoint.sh
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=3s --retries=3 CMD curl -fsS http://127.0.0.1:8080/ || exit 1
|
||||
# Expose both ports (Flet 8080 and Flask 9000)
|
||||
EXPOSE 8080 9000
|
||||
|
||||
# Run entrypoint to create superuser and start the app
|
||||
ENTRYPOINT ["sh", "-c", "python create_super_user.py && python main.py"]
|
||||
# Use the script to start the container
|
||||
ENTRYPOINT ["./entrypoint.sh"]
|
||||
@@ -38,6 +38,15 @@ class AdminChat:
|
||||
on_click=self.on_send_click,
|
||||
)
|
||||
|
||||
# Notification sound to be played on new client messages
|
||||
# Make sure the file path points to a valid audio file in your assets.
|
||||
# Example: place `chat_notify.mp3` in `assets/sounds/`.
|
||||
self.notification_audio = ft.Audio(
|
||||
src="assets/sounds/chat_notify_triple.mp3",
|
||||
autoplay=True,
|
||||
volume=1.0,
|
||||
)
|
||||
|
||||
# Subscribe to PubSub for live updates from clients
|
||||
try:
|
||||
self.page.pubsub.subscribe(self.on_pubsub_message)
|
||||
@@ -107,7 +116,19 @@ class AdminChat:
|
||||
vertical_alignment=ft.CrossAxisAlignment.CENTER,
|
||||
controls=[
|
||||
self.header_label,
|
||||
ft.Icon(ft.Icons.SUPPORT_AGENT),
|
||||
ft.Row(
|
||||
[
|
||||
ft.Icon(ft.Icons.SUPPORT_AGENT),
|
||||
ft.WebView(
|
||||
url="/enable-notifications", # small HTML page with a single 'Activează notificările' button
|
||||
width=160,
|
||||
height=40,
|
||||
expand=False,
|
||||
),
|
||||
],
|
||||
vertical_alignment=ft.CrossAxisAlignment.CENTER,
|
||||
spacing=8,
|
||||
),
|
||||
],
|
||||
),
|
||||
ft.Divider(),
|
||||
@@ -120,6 +141,7 @@ class AdminChat:
|
||||
vertical_alignment=ft.CrossAxisAlignment.CENTER,
|
||||
controls=[self.input_field, self.send_button],
|
||||
),
|
||||
self.notification_audio,
|
||||
],
|
||||
),
|
||||
)
|
||||
@@ -165,7 +187,7 @@ class AdminChat:
|
||||
title = f"Chat #{chat_id}"
|
||||
if user_id:
|
||||
user = self.user_namager.get(user_id)
|
||||
title += f" • User {user['name'].replace("~", " ")}"
|
||||
title += f" • User {user['name'].replace('~', ' ')}"
|
||||
|
||||
subtitle_parts = []
|
||||
if status == "open":
|
||||
@@ -232,7 +254,7 @@ class AdminChat:
|
||||
label = f"Chat #{chat_id}"
|
||||
if user_id:
|
||||
user = self.user_namager.get(user_id)
|
||||
label += f" • User {user['name'].replace("~", " ")}"
|
||||
label += f" • User {user['name'].replace('~', ' ')}"
|
||||
self.header_label.value = label
|
||||
else:
|
||||
self.header_label.value = f"Chat #{chat_id}"
|
||||
@@ -362,6 +384,14 @@ class AdminChat:
|
||||
if data.get("type") == "chat_message" and data.get("sender") == "client":
|
||||
chat_id = data.get("chat_id")
|
||||
|
||||
# Play notification sound for any incoming client message
|
||||
try:
|
||||
print('Play sound')
|
||||
self.notification_audio.play()
|
||||
print('Played sound')
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
# If this is the currently open chat, append bubble directly
|
||||
if self.active_chat_id == chat_id:
|
||||
text = data.get("text", "")
|
||||
|
||||
BIN
UI_V2/assets/sounds/chat_notify.wav
Normal file
BIN
UI_V2/assets/sounds/chat_notify.wav
Normal file
Binary file not shown.
BIN
UI_V2/assets/sounds/chat_notify_triple.wav
Normal file
BIN
UI_V2/assets/sounds/chat_notify_triple.wav
Normal file
Binary file not shown.
14
UI_V2/chat/chat.py
Normal file
14
UI_V2/chat/chat.py
Normal file
@@ -0,0 +1,14 @@
|
||||
import flet as ft
|
||||
|
||||
class Chat:
|
||||
def __init__(self, page: ft.Page):
|
||||
self.page = page
|
||||
|
||||
def build(self):
|
||||
return ft.Container(
|
||||
content=ft.Column(
|
||||
[
|
||||
ft.Text("Aveti nevoie de ajutor?")
|
||||
]
|
||||
)
|
||||
)
|
||||
@@ -25,6 +25,7 @@ services:
|
||||
# SHOP_DB_PATH: "/app/instance/shop.db" # custom var
|
||||
expose:
|
||||
- "8080"
|
||||
- "9000"
|
||||
volumes:
|
||||
- tg_instance:/app/instance
|
||||
- tg_assets:/app/assets
|
||||
|
||||
12
UI_V2/entrypoint.sh
Normal file
12
UI_V2/entrypoint.sh
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
|
||||
# 1. Run your superuser script
|
||||
python create_super_user.py
|
||||
|
||||
# 2. Start Flask in the background (&)
|
||||
# We use & to let it run while the script continues
|
||||
python flask_server.py &
|
||||
|
||||
# 3. Start Flet (Main process)
|
||||
# This stays in the foreground so the container doesn't exit
|
||||
python main.py
|
||||
62
UI_V2/flask_server.py
Normal file
62
UI_V2/flask_server.py
Normal file
@@ -0,0 +1,62 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import logging
|
||||
from logging.handlers import RotatingFileHandler
|
||||
from flask import Flask, request, jsonify
|
||||
from flask_cors import CORS
|
||||
|
||||
try:
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
from UI_V2.helpers.netopia import verify_ipn, get_status
|
||||
|
||||
app = Flask(__name__)
|
||||
CORS(app, resources={r"/api/*": {"origins": "*"}})
|
||||
|
||||
# ---------- Logging ----------
|
||||
app.logger.setLevel(logging.INFO)
|
||||
_log_dir = os.getenv("LOG_DIR", "logs")
|
||||
os.makedirs(_log_dir, exist_ok=True)
|
||||
_handler = RotatingFileHandler(os.path.join(_log_dir, "netopia_api.log"), maxBytes=1_000_000, backupCount=3)
|
||||
_handler.setLevel(logging.INFO)
|
||||
_handler.setFormatter(logging.Formatter("%(asctime)s [%(levelname)s] %(message)s"))
|
||||
app.logger.addHandler(_handler)
|
||||
|
||||
|
||||
@app.get("/healthz")
|
||||
def healthz():
|
||||
return {"ok": True}, 200
|
||||
|
||||
@app.post("/api/payments/ipn")
|
||||
def ipn():
|
||||
try:
|
||||
raw = request.data
|
||||
data = verify_ipn(raw)
|
||||
app.logger.info("IPN OK: %s", data)
|
||||
return jsonify({"ok": True, "data": data}), 200
|
||||
except Exception as e:
|
||||
app.logger.exception("IPN verification failed: %s", e)
|
||||
return jsonify({"ok": False, "error": str(e)}), 400
|
||||
|
||||
|
||||
@app.get("/api/payments/status")
|
||||
def status():
|
||||
ntp_id = request.args.get("ntpID")
|
||||
order_id = request.args.get("orderID")
|
||||
try:
|
||||
resp = get_status(ntp_id=ntp_id, order_id=order_id)
|
||||
return jsonify({"ok": True, "data": resp}), 200
|
||||
except Exception as e:
|
||||
app.logger.exception("Status query failed: %s", e)
|
||||
return jsonify({"ok": False, "error": str(e)}), 400
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
host = os.getenv("API_HOST", "0.0.0.0")
|
||||
port = int(os.getenv("API_PORT", "9000"))
|
||||
app.logger.info("Starting NETOPIA Flask sidecar on %s:%s", host, port)
|
||||
app.run(host=host, port=port)
|
||||
@@ -22,7 +22,7 @@ from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
def main(page: ft.Page):
|
||||
page.title = "Taina Gustului"
|
||||
page.title = "Taina Gustului - Condimente, nuci și fructe uscate în Craiova"
|
||||
page.theme_mode = ft.ThemeMode.LIGHT
|
||||
page.theme = ft.Theme(color_scheme=ft.ColorScheme(primary=ft.Colors.BROWN))
|
||||
page.vertical_alignment = ft.MainAxisAlignment.CENTER
|
||||
|
||||
Reference in New Issue
Block a user