11<!DOCTYPE html>
22< html lang ="en ">
33< head >
4- < meta charset ="UTF-8 ">
5- < meta name ="viewport " content ="width=device-width, initial-scale=1.0 ">
6- < title > SBM Smart Maintenance System</ title >
7- < link href ="https://fonts.googleapis.com/css2?family=Orbitron:wght@500;700&family=Roboto:wght@300;400;700&display=swap " rel ="stylesheet ">
8-
9- < style >
10- : root { --primary : # FFA500 ; --bg : # 0f1117 ; --card : # 1c1f26 ; --text : # e6edf3 ; --accent : # 39FF14 ; --danger : # ff4444 ; }
11- body { margin : 0 ; background : var (--bg ); color : var (--text ); font-family : 'Roboto' , sans-serif; }
12- header { text-align : center; padding : 20px ; background : linear-gradient (180deg , # FFA500, # 111 ); border-radius : 0 0 20px 20px ; }
13- header h1 { margin : 0 ; font-family : 'Orbitron' , sans-serif; font-size : 18px ; color : # 000 ; }
14- .container { max-width : 700px ; margin : auto; padding : 15px ; }
15- .card { background : var (--card ); padding : 15px ; border-radius : 12px ; margin : 15px 0 ; border : 1px solid # 30363d ; }
16- h2 { color : var (--primary ); font-size : 16px ; margin-top : 0 ; border-bottom : 1px solid # 333 ; padding-bottom : 5px ;}
17- input , select , textarea , button { width : 100% ; padding : 12px ; margin : 8px 0 ; border-radius : 8px ; border : none; font-size : 14px ; box-sizing : border-box; }
18- input , select , textarea { background : # 0d1117 ; color : white; border : 1px solid # 444 ; }
19- button { background : var (--primary ); font-weight : bold; cursor : pointer; color : # 000 ; }
20- .btn-secondary { background : # 444 ; color : white; margin-top : 5px ; }
21- .dashboard-item { border-bottom : 1px solid # 333 ; padding : 12px 0 ; display : flex; justify-content : space-between; align-items : center; gap : 10px ; }
22- .status-badge { padding : 4px 8px ; border-radius : 4px ; font-size : 10px ; font-weight : bold; text-transform : uppercase; }
23- .status-pending { background : # 555 ; color : white; }
24- .status-done { background : var (--accent ); color : black; }
25- .btn-action { width : auto; padding : 6px 12px ; font-size : 11px ; margin : 0 2px ; }
26- .whatsapp { position : fixed; bottom : 20px ; right : 20px ; z-index : 1000 ; }
27- # mainApp { display : none; } /* Login gochuu dura ni dhokata */
28- </ style >
4+ < meta charset ="UTF-8 ">
5+ < meta name ="viewport " content ="width=device-width, initial-scale=1.0 ">
6+ < title > SBM Smart AI - Full Project</ title >
7+ < link href ="https://fonts.googleapis.com/css2?family=Orbitron:wght@500;700&family=Roboto:wght@300;400;700&display=swap " rel ="stylesheet ">
8+ < link rel ="stylesheet " href ="dashboard/dashboard.css ">
9+ < style >
10+ : root { --primary : # FFA500 ; --bg : # 0f1117 ; --card : # 1c1f26 ; --text : # e6edf3 ; --accent : # 39FF14 ; --danger : # ff4444 ; }
11+ body { margin : 0 ; background : var (--bg ); color : var (--text ); font-family : 'Roboto' , sans-serif; }
12+ header { text-align : center; padding : 20px ; background : linear-gradient (180deg , # FFA500, # 111 ); border-radius : 0 0 20px 20px ; }
13+ header h1 { margin : 0 ; font-family : 'Orbitron' , sans-serif; font-size : 22px ; color : # 000 ; }
14+ .container { max-width : 800px ; margin : auto; padding : 15px ; }
15+ .card { background : var (--card ); padding : 20px ; border-radius : 15px ; margin : 15px 0 ; border : 1px solid # 30363d ; box-shadow : 0 4px 15px rgba (0 , 0 , 0 , 0.5 ); }
16+ h2 { color : var (--primary ); font-size : 18px ; margin-top : 0 ; border-bottom : 1px solid # 333 ; padding-bottom : 10px ;}
17+ input , select , textarea , button { width : 100% ; padding : 14px ; margin : 10px 0 ; border-radius : 10px ; border : none; font-size : 14px ; box-sizing : border-box; background : # 0d1117 ; color : white; }
18+ button { background : var (--primary ); color : # 000 ; font-weight : bold; cursor : pointer; }
19+ # mainApp { display : none; }
20+ .nav-links { display : flex; justify-content : space-around; margin-bottom : 20px ; }
21+ .nav-links a { color : var (--primary ); text-decoration : none; font-weight : bold; font-size : 12px ; }
22+ </ style >
2923</ head >
30-
3124< body >
3225
3326< header >
3427 < h1 > ABDURHAMAN MECHATRONICS</ h1 >
35- < p > Secure Cloud Maintenance System </ p >
28+ < p > AI-Powered Integrated Maintenance</ p >
3629</ header >
3730
3831< div class ="container ">
39-
4032 < div id ="loginSection " class ="card ">
41- < h2 > 👤 Admin Access</ h2 >
42- < p style ="font-size: 12px; color: #888; "> Enter email and password to manage system.</ p >
43- < input type ="email " id ="email " placeholder ="Email (example@gmail.com) ">
33+ < h2 > 🔐 Admin Access</ h2 >
34+ < input type ="email " id ="email " placeholder ="Email ">
4435 < input type ="password " id ="password " placeholder ="Password ">
4536 < button onclick ="login() "> SIGN IN</ button >
46- < button onclick ="signUp() " class ="btn-secondary "> CREATE NEW ACCOUNT (SIGN UP)</ button >
47- < p id ="authMsg " style ="font-size: 12px; text-align: center; margin-top: 10px; "> </ p >
4837 </ div >
4938
5039 < div id ="mainApp ">
51- < button onclick ="logout() " style ="background: #333; color: white; width: auto; font-size: 12px; float: right; "> LOGOUT</ button >
52- < div style ="clear: both; "> </ div >
53-
54- < div class ="card ">
55- < h2 > 🛠️ New Service Report</ h2 >
56- < input type ="text " id ="customer " placeholder ="Customer Name ">
57- < select id ="machine ">
58- < option value =""> Select Machine</ option >
59- < option > Jaw Crusher (PE/PEW)</ option >
60- < option > Cone Crusher (HP/HST)</ option >
61- < option > SBM Vibrating Screen</ option >
62- < option > VSI Crusher</ option >
63- </ select >
64- < textarea id ="issue " placeholder ="Describe fault & parts used... "> </ textarea >
65- < button onclick ="saveReport() "> SAVE TO CLOUD</ button >
40+ < div class ="nav-links ">
41+ < a href ="dashboard/dashboard.html "> 📊 DASHBOARD</ a >
42+ < a href ="image-ai/upload.html "> 📸 AI SCANNER</ a >
43+ < button onclick ="logout() " style ="width:auto; background:red; color:white; padding:5px 10px; margin:0; "> LOGOUT</ button >
6644 </ div >
6745
6846 < div class ="card ">
69- < h2 > 📦 Spare Parts Inventory </ h2 >
70- < input type ="text " id ="partName " placeholder =" Part Name ">
71- < input type =" number " id =" partQty " placeholder =" Quantity " >
72- < button onclick =" addPart() " style =" background:var(--accent) " > Add Part </ button >
73- < div id =" partsList " > </ div >
47+ < h2 > 🛠️ AI Machine Analysis </ h2 >
48+ < input type ="file " id ="imgFile " accept =" image/* ">
49+ < button onclick =" runVisionAI() " style =" background:var(--accent); color:#000; " > ANALYZE WITH AI </ button >
50+ < textarea id =" issue " placeholder =" AI Analysis result... " > </ textarea >
51+ < button onclick =" saveReport() " > SAVE TO CLOUD </ button >
7452 </ div >
7553
7654 < div class ="card ">
77- < h2 > 📈 Live Dashboard</ h2 >
78- < input type ="text " id ="searchInput " onkeyup ="searchData() " placeholder ="🔍 Search customer or machine... ">
79- < p style ="font-size: 12px; color: var(--primary); "> Total Reports: < span id ="totalCount "> 0</ span > </ p >
55+ < h2 > 📈 Service Dashboard</ h2 >
8056 < div id ="reportList "> </ div >
8157 </ div >
8258 </ div >
8359</ div >
8460
85- < a href ="https://wa.me/251904267186 " class ="whatsapp " target ="_blank ">
86- < img src ="https://upload.wikimedia.org/wikipedia/commons/6/6b/WhatsApp.svg " width ="50 ">
87- </ a >
88-
8961< script src ="https://www.gstatic.com/firebasejs/9.23.0/firebase-app-compat.js "> </ script >
9062< script src ="https://www.gstatic.com/firebasejs/9.23.0/firebase-auth-compat.js "> </ script >
9163< script src ="https://www.gstatic.com/firebasejs/9.23.0/firebase-firestore-compat.js "> </ script >
9264
65+ < script type ="module ">
66+ import { analyzeImage } from './api/vision-ai.js' ;
67+ window . runVisionAI = async ( ) => {
68+ const file = document . getElementById ( "imgFile" ) . files [ 0 ] ;
69+ if ( ! file ) return alert ( "Select an image!" ) ;
70+ const reader = new FileReader ( ) ;
71+ reader . readAsDataURL ( file ) ;
72+ reader . onload = async ( ) => {
73+ document . getElementById ( "issue" ) . value = "🔄 AI is analyzing..." ;
74+ try {
75+ const data = await analyzeImage ( reader . result ) ;
76+ document . getElementById ( "issue" ) . value = data . choices [ 0 ] . message . content ;
77+ } catch ( err ) {
78+ document . getElementById ( "issue" ) . value = "❌ API Error or Key Missing." ;
79+ }
80+ } ;
81+ } ;
82+ </ script >
83+
9384< script >
94- // Firebase Configuration
9585const firebaseConfig = {
9686 apiKey : "AIzaSyC1_0Ptpna4V-2cfyJHNwIvWvbA2eGLv18" ,
9787 authDomain : "sbm-app-ecf59.firebaseapp.com" ,
@@ -101,109 +91,41 @@ <h2>📈 Live Dashboard</h2>
10191 appId : "1:666387083873:web:bfd6d5e064ecaad6c73020"
10292} ;
10393
104- // Initialize Firebase
10594if ( ! firebase . apps . length ) { firebase . initializeApp ( firebaseConfig ) ; }
10695const auth = firebase . auth ( ) ;
10796const db = firebase . firestore ( ) ;
10897
109- // --- AUTHENTICATION FUNCTIONS ---
11098function login ( ) {
11199 const e = document . getElementById ( "email" ) . value ;
112100 const p = document . getElementById ( "password" ) . value ;
113- auth . signInWithEmailAndPassword ( e , p )
114- . catch ( err => document . getElementById ( "authMsg" ) . innerText = "❌ " + err . message ) ;
115- }
116-
117- function signUp ( ) {
118- const e = document . getElementById ( "email" ) . value ;
119- const p = document . getElementById ( "password" ) . value ;
120- auth . createUserWithEmailAndPassword ( e , p )
121- . then ( ( ) => alert ( "Account Created! You can now Login." ) )
122- . catch ( err => document . getElementById ( "authMsg" ) . innerText = "❌ " + err . message ) ;
123- }
124-
125- function logout ( ) {
126- auth . signOut ( ) ;
101+ auth . signInWithEmailAndPassword ( e , p ) . catch ( err => alert ( err . message ) ) ;
127102}
128-
129- // Manage User State
103+ function logout ( ) { auth . signOut ( ) ; }
130104auth . onAuthStateChanged ( user => {
131- if ( user ) {
132- document . getElementById ( "loginSection" ) . style . display = "none" ;
133- document . getElementById ( "mainApp" ) . style . display = "block" ;
134- } else {
135- document . getElementById ( "loginSection" ) . style . display = "block" ;
136- document . getElementById ( "mainApp" ) . style . display = "none" ;
137- }
105+ document . getElementById ( "loginSection" ) . style . display = user ? "none" : "block" ;
106+ document . getElementById ( "mainApp" ) . style . display = user ? "block" : "none" ;
138107} ) ;
139108
140- // --- DATABASE FUNCTIONS ---
141109function saveReport ( ) {
142- const c = document . getElementById ( "customer" ) . value ;
143- const m = document . getElementById ( "machine" ) . value ;
144110 const i = document . getElementById ( "issue" ) . value ;
145- if ( ! c || ! m || ! i ) return alert ( "Fill all fields" ) ;
146-
111+ if ( ! i ) return alert ( "No data" ) ;
147112 db . collection ( "reports" ) . add ( {
148- customer : c , machine : m , issue : i , status : "pending" ,
113+ issue : i , status : "pending" ,
149114 time : firebase . firestore . FieldValue . serverTimestamp ( )
150- } ) . then ( ( ) => {
151- document . getElementById ( "customer" ) . value = "" ;
152- document . getElementById ( "issue" ) . value = "" ;
153- } ) ;
115+ } ) . then ( ( ) => alert ( "Saved!" ) ) ;
154116}
155117
156- function addPart ( ) {
157- const name = document . getElementById ( "partName" ) . value ;
158- const qty = document . getElementById ( "partQty" ) . value ;
159- if ( ! name || ! qty ) return ;
160- db . collection ( "inventory" ) . add ( { name : name , quantity : qty } ) ;
161- }
162-
163- // Real-time Listeners
164118db . collection ( "reports" ) . orderBy ( "time" , "desc" ) . onSnapshot ( snapshot => {
165- document . getElementById ( "totalCount" ) . innerText = snapshot . size ;
166119 const list = document . getElementById ( "reportList" ) ;
167120 list . innerHTML = "" ;
168121 snapshot . forEach ( doc => {
169122 const d = doc . data ( ) ;
170- const date = d . time ? d . time . toDate ( ) . toLocaleDateString ( ) : "..." ;
171- const statusClass = d . status === 'done' ? 'status-done' : 'status-pending' ;
172- list . innerHTML += `
173- <div class="dashboard-item">
174- <div>
175- <strong>${ d . customer } </strong> <span class="status-badge ${ statusClass } ">${ d . status } </span><br>
176- <small>${ d . machine } | ${ date } </small><br>
177- <span style="font-size:12px;">${ d . issue } </span>
178- </div>
179- <div>
180- <button class="btn-action" style="background:var(--accent)" onclick="db.collection('reports').doc('${ doc . id } ').update({status:'done'})">✔</button>
181- <button class="btn-action" style="background:var(--danger); color:white" onclick="if(confirm('Delete?')) db.collection('reports').doc('${ doc . id } ').delete()">X</button>
182- </div>
183- </div>` ;
184- } ) ;
185- } ) ;
186-
187- db . collection ( "inventory" ) . onSnapshot ( snapshot => {
188- const list = document . getElementById ( "partsList" ) ;
189- list . innerHTML = "" ;
190- snapshot . forEach ( doc => {
191- const d = doc . data ( ) ;
192- list . innerHTML += `
193- <div class="dashboard-item">
194- <span>${ d . name } : ${ d . quantity } </span>
195- <button class="btn-action" style="background:#444; color:white" onclick="db.collection('inventory').doc('${ doc . id } ').delete()">X</button>
123+ list . innerHTML += `<div style="padding:10px; border-bottom:1px solid #333;">
124+ <small>${ d . time ? d . time . toDate ( ) . toLocaleString ( ) : '' } </small><br>
125+ <span>${ d . issue } </span>
196126 </div>` ;
197127 } ) ;
198128} ) ;
199-
200- function searchData ( ) {
201- let input = document . getElementById ( 'searchInput' ) . value . toLowerCase ( ) ;
202- let items = document . getElementsByClassName ( 'dashboard-item' ) ;
203- for ( let i = 0 ; i < items . length ; i ++ ) {
204- items [ i ] . style . display = items [ i ] . innerText . toLowerCase ( ) . includes ( input ) ? "" : "none" ;
205- }
206- }
207129</ script >
208130</ body >
209131</ html >
0 commit comments