Prechádzať zdrojové kódy

update ips printers

Erwin Jacimino 8 mesiacov pred
rodič
commit
2de5f678e9

+ 79 - 21
public/main/js/app.js

@@ -28,6 +28,23 @@ let cacheMode = false;
 
 // --- Configuration ---
 const favoriteCategories = ["Shop", "Pizzas Familiares", "Pizza Medianas"];
+const productPriority = {
+    "Shop": [
+        6, 12, 163, 168, 15, 665, 1
+    ],
+    "Cervezas": [
+        17, 
+    ],
+    "Coctelería Gin Klein": [
+        655
+    ],
+    "Pizzas Familiares": [
+        27
+    ],
+    "Pizza Medianas": [
+        2
+    ]
+}
 
 // --- Chat History ---
 let chatHistory = [
@@ -166,7 +183,7 @@ function initializeLoginModal() {
             userToken = null;
             cacheMode = false;
             hideGUI();
-            sessionModal.classList.remove('hidden');
+            sessionModal.classList.remove('hidden');false
             
             // Reset UI elements
             document.querySelector("#emailInputContainer").classList.remove("hidden");
@@ -355,7 +372,7 @@ function setupSearchListener() {
             }
             
             const foundProducts = smartSearch(Allproducts, searchTerm);
-            renderProductsWithAnimation(foundProducts, false, searchTerm);
+            renderProductsWithAnimation(foundProducts, true, searchTerm);
         }, 200);
     });
 }
@@ -521,7 +538,28 @@ async function renderProducts(products, groupInCategories = true, searchTerm = "
         let productsInCategory = groupInCategories 
             ? products.filter(product => product.type === category)
             : products;
-
+        // Prioritize products in favorite categories
+        if (favoriteCategories.includes(category) && productPriority[category]) {
+            productsInCategory.sort((a, b) => {
+            const aIndex = productPriority[category].indexOf(a.id);
+            const bIndex = productPriority[category].indexOf(b.id);
+            
+            // If both products are in priority list, sort by their priority order
+            if (aIndex !== -1 && bIndex !== -1) {
+                return aIndex - bIndex;
+            }
+            // If only 'a' is in priority list, it should come first
+            if (aIndex !== -1 && bIndex === -1) {
+                return -1;
+            }
+            // If only 'b' is in priority list, it should come first
+            if (aIndex === -1 && bIndex !== -1) {
+                return 1;
+            }
+            // If neither is in priority list, maintain original order
+            return 0;
+            });
+        }
         if (productsInCategory.length === 0) continue;
 
         productsInCategory.forEach(product => {
@@ -568,6 +606,13 @@ async function renderProductsWithAnimation(products, groupInCategories = true, s
             categoryContainers = [{ category: searchTerm, container: productListElement }];
         }
         
+        // ordenar las categorias por favoriteCategories
+        categoryContainers.sort((a, b) => {
+            const aIndex = favoriteCategories.indexOf(a.category);
+            const bIndex = favoriteCategories.indexOf(b.category);
+            return aIndex - bIndex;
+        });
+
         if (products.length === 0) {
             const noProductsMessage = document.createElement("p");
             noProductsMessage.textContent = "No hay productos disponibles.";
@@ -596,6 +641,28 @@ async function renderProductsWithAnimation(products, groupInCategories = true, s
 
             if (productsInCategory.length === 0) continue;
 
+            if (favoriteCategories.includes(category) && productPriority[category]) {
+            productsInCategory.sort((a, b) => {
+            const aIndex = productPriority[category].indexOf(a.id);
+            const bIndex = productPriority[category].indexOf(b.id);
+            
+            // If both products are in priority list, sort by their priority order
+            if (aIndex !== -1 && bIndex !== -1) {
+                return aIndex - bIndex;
+            }
+            // If only 'a' is in priority list, it should come first
+            if (aIndex !== -1 && bIndex === -1) {
+                return -1;
+            }
+            // If only 'b' is in priority list, it should come first
+            if (aIndex === -1 && bIndex !== -1) {
+                return 1;
+            }
+            // If neither is in priority list, maintain original order
+            return 0;
+            });
+        }
+
             productsInCategory.forEach((product, index) => {
                 const clone = template.content.cloneNode(true);
 
@@ -946,6 +1013,15 @@ function initializeRewards() {
         closeModal();
     });
 
+    // Close model - Back button on phone
+    WindowEventHandlers.onpopstate = function (event) {
+        if (!rewardModal.classList.contains('hidden')) {
+            event.preventDefault();
+            event.stopPropagation();
+            closeModal();
+        }
+    }
+
     // Close modal - click outside
     rewardModal.addEventListener('click', function (e) {
         if (e.target === rewardModal) {
@@ -1003,24 +1079,6 @@ function closeModal() {
     claimRewardBtn.classList.add('opacity-50', 'cursor-not-allowed');
 }
 
-
-
-/**
- * Reset reward progress to 0%
- */
-function resetRewardProgress() {
-    const progressBar = document.getElementById('progressBar');
-    const progressText = document.getElementById('progressText');
-    const rewardBtn = document.getElementById('rewardBtn');
-
-    progressBar.style.width = '0%';
-    progressText.textContent = '0%';
-
-    rewardBtn.disabled = true;
-    rewardBtn.classList.add('opacity-50', 'cursor-not-allowed');
-    rewardBtn.classList.remove('bg-yellow-500', 'hover:bg-yellow-600');
-    rewardBtn.textContent = '🎉 ¡Reclamar!';
-}
 //--- Inicialización de la Aplicación ---
 
 /**

+ 2 - 2
public/register/index.html

@@ -17,7 +17,7 @@
 
     <!-- === MODAL DE REGISTRO === -->
     <div id="registerModal"
-         class="hidden inset-0 bg-black/70 flex items-center justify-center z-50 p-4">
+         class="inset-0 bg-black/70 flex items-center justify-center z-50 p-4">
       <form id="registerForm" class="bg-white w-full max-w-md p-8 rounded-xl shadow-xl space-y-6">
         <div class="text-center">
           <h2 class="text-2xl font-bold text-gray-900">¡Regístrate!</h2>
@@ -79,7 +79,7 @@
     </div>
 
         <!-- === PÁGINA DE REGISTRO EXITOSO === -->
-    <div id="successPage" class=" min-h-screen bg-gray-100 flex items-center justify-center p-4">
+    <div id="successPage" class="hidden min-h-screen bg-gray-100 flex items-center justify-center p-4">
       <div class="bg-white w-full max-w-lg p-10 rounded-xl shadow-xl space-y-8 text-center">
         <!-- Icono de éxito -->
         <div class="flex justify-center">

+ 18 - 4
routes/chat.py

@@ -8,7 +8,7 @@ from broadcaster import Broadcast
 
 from config.settings import DEVELOPMENT
 from models.user import User
-from services.openai_service.openai_service import generate_completion
+from services.openai_service.openai_service import generate_completion, admin_completion
 from auth.security import get_current_user
 from redis import Redis
 
@@ -81,7 +81,8 @@ async def chat_irc_endpoint(websocket: WebSocket):
                     message_username = payload["username"]
                     message = payload["message"]
                     response = {"type": "message", "username": message_username, "message": message}
-
+                    redis_client.rpush("chat_history", json.dumps(response))
+                    redis_client.ltrim("chat_history", -100, -1)  # Keep only
                 elif event_type == "leave":
                     logger.info(f"User {payload['username']} left the chat.")
                     message_username = payload["username"]
@@ -96,11 +97,16 @@ async def chat_irc_endpoint(websocket: WebSocket):
                     await websocket.close()
                     break
                 elif event_type == "ai_message":
+                    messages = redis_client.lrange("chat_history", -15, -1)
+                    parsed_messages = [json.loads(msg) for msg in messages]
                     logger.debug(f"IA Message from {payload['username']}: {payload['messages']}")
                     message_username = payload["username"]
-                    messages = payload["messages"]
-                    response_content = await generate_completion(messages, current_user)
+                    response_content = await generate_completion(parsed_messages, current_user)
                     response = {"type": "message", "username": "IAKlein", "message": response_content}
+                elif event_type == "notification":
+                    logger.debug(f"Notification to {payload['username']}: {payload['message']}")
+                    notification_message = payload["message"]
+                    
                 elif event_type == "mention":
                     logger.debug(f"Mention to {payload['username']}")
                     mention_username = payload["username"]
@@ -133,6 +139,14 @@ async def chat_irc_endpoint(websocket: WebSocket):
         reader_task.cancel()
         await broadcast.disconnect()
 
+@chat_router.post("/notify")
+async def notify_users(message: str, _: User = Depends(get_current_user)):
+    """Send a notification message to all connected users"""
+    broadcast = Broadcast("redis://localhost:6379")
+    await broadcast.connect()
+    await broadcast.publish(channel="chat", message=json.dumps({"type": "notification", "message": message}))
+    await broadcast.disconnect()
+    return {"status": "Notification sent"}
 
 @chat_router.get("/users")
 async def get_connected_users(q: Optional[str] = Query(None), _: User = Depends(get_current_user)):

+ 21 - 0
services/openai_service/openai_service.py

@@ -78,3 +78,24 @@ Estilo:
     except Exception as e:
         logger.error(f"Error calling OpenAI: {e}")
         raise HTTPException(status_code=500, detail="Error al procesar tu solicitud con OpenAI.")
+
+def admin_completion(prompt: str) -> str:
+    """Generate OpenAI admin completion"""
+    if not OPENAI_API_KEY:
+        logger.error("Error: OpenAI API key is not configured.")
+        raise HTTPException(status_code=500, detail="OpenAI API key not configured on server.")
+
+    try:
+        completion = openai_client.chat.completions.create(
+            model="gpt-4o-mini",
+            messages=[
+                {"role": "system", "content": "Eres un asistente administrativo que ayuda a gestionar el bar Klein. Responde de forma profesional y concisa."},
+                {"role": "user", "content": prompt}
+            ],
+            temperature=0.3,
+        )
+        response_content = completion.choices[0].message.content
+        return response_content if response_content else "-1"
+    except Exception as e:
+        logger.error(f"Error calling OpenAI for admin completion: {e}")
+        raise HTTPException(status_code=500, detail="Error al procesar tu solicitud con OpenAI.")