repair realtime conection with realtime firebase + togle button
This commit is contained in:
parent
193d4a04c2
commit
9d3be56527
|
@ -16,3 +16,5 @@ yarn-error.log
|
|||
/.fleet
|
||||
/.idea
|
||||
/.vscode
|
||||
!storage/app/*.json
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <FirebaseESP8266.h>
|
||||
#include <DHT.h>
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class ProfileController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return view('profile', [
|
||||
'user' => Auth::user()
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required|email',
|
||||
'current_password' => 'required_with:new_password',
|
||||
'new_password' => 'nullable|min:8|confirmed',
|
||||
'profile_photo' => 'nullable|image|mimes:jpeg,png,jpg|max:2048'
|
||||
]);
|
||||
|
||||
$user = Auth::user();
|
||||
$user->email = $request->email;
|
||||
|
||||
// Handle password change
|
||||
if ($request->new_password) {
|
||||
if (!Hash::check($request->current_password, $user->password)) {
|
||||
return back()->withErrors(['current_password' => 'Current password is incorrect']);
|
||||
}
|
||||
$user->password = Hash::make($request->new_password);
|
||||
}
|
||||
|
||||
// Handle profile photo
|
||||
if ($request->hasFile('profile_photo')) {
|
||||
$photo = $request->file('profile_photo');
|
||||
|
||||
// Replace existing foto.jpg
|
||||
$photo->move(public_path('asset'), 'foto.jpg');
|
||||
}
|
||||
|
||||
$user->save();
|
||||
|
||||
return redirect()->back()->with('success', 'Profile updated successfully');
|
||||
}
|
||||
}
|
|
@ -13,16 +13,16 @@ public function register()
|
|||
{
|
||||
$this->app->singleton(FirebaseAuth::class, function ($app) {
|
||||
$factory = (new Factory)
|
||||
->withServiceAccount(json_decode(env('FIREBASE_CREDENTIALS'), true))
|
||||
->withDatabaseUri(env('FIREBASE_DATABASE_URL'));
|
||||
->withServiceAccount(storage_path('app/smartcab-8bb42-firebase-adminsdk-fbsvc-de33a8e45b.json'))
|
||||
->withDatabaseUri(env('FIREBASE_DATABASE_URL'));
|
||||
|
||||
return $factory->createAuth();
|
||||
});
|
||||
|
||||
$this->app->singleton(Database::class, function ($app) {
|
||||
$factory = (new Factory)
|
||||
->withServiceAccount(config('firebase.credentials'))
|
||||
->withDatabaseUri(config('firebase.database_url'));
|
||||
->withServiceAccount(storage_path('app/smartcab-8bb42-firebase-adminsdk-fbsvc-de33a8e45b.json'))
|
||||
->withDatabaseUri(env('FIREBASE_DATABASE_URL'));
|
||||
|
||||
return $factory->createDatabase();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Profile - SmartCab</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</head>
|
||||
<body class="bg-gray-100 dark:bg-gray-900">
|
||||
<div class="min-h-screen p-6">
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<!-- Header -->
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h1 class="text-2xl font-bold text-gray-800 dark:text-white">Your Profile</h1>
|
||||
<a href="{{ route('welcome') }}" class="px-4 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600">
|
||||
Back to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@if(session('success'))
|
||||
<div class="mb-4 p-4 bg-green-100 border border-green-400 text-green-700 rounded">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($errors->any())
|
||||
<div class="mb-4 p-4 bg-red-100 border border-red-400 text-red-700 rounded">
|
||||
<ul>
|
||||
@foreach($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('profile.update') }}" method="POST" enctype="multipart/form-data" class="bg-white dark:bg-gray-800 rounded-lg shadow-lg p-6">
|
||||
@csrf
|
||||
|
||||
<!-- Profile Photo -->
|
||||
<div class="mb-6">
|
||||
<label class="block text-gray-700 dark:text-gray-200 text-sm font-bold mb-2">Profile Photo</label>
|
||||
<div class="flex items-center space-x-6">
|
||||
<div class="shrink-0">
|
||||
<img id="preview" class="h-32 w-32 object-cover rounded-full" src="{{ asset('asset/foto.jpg') }}" alt="Current profile photo">
|
||||
</div>
|
||||
<label class="block">
|
||||
<span class="sr-only">Choose profile photo</span>
|
||||
<input type="file" name="profile_photo" id="profile_photo"
|
||||
class="block w-full text-sm text-gray-500 dark:text-gray-300
|
||||
file:mr-4 file:py-2 file:px-4
|
||||
file:rounded-full file:border-0
|
||||
file:text-sm file:font-semibold
|
||||
file:bg-blue-50 file:text-blue-700
|
||||
hover:file:bg-blue-100
|
||||
dark:file:bg-gray-700 dark:file:text-white"
|
||||
accept="image/*"
|
||||
onchange="updatePreview(this)"/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Email -->
|
||||
<div class="mb-6">
|
||||
<label for="email" class="block text-gray-700 dark:text-gray-200 text-sm font-bold mb-2">Email Address</label>
|
||||
<input type="email" name="email" id="email" value="{{ Auth::user()->email }}"
|
||||
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 dark:text-gray-300 dark:bg-gray-700 leading-tight focus:outline-none focus:shadow-outline">
|
||||
</div>
|
||||
|
||||
<!-- Password Change Section -->
|
||||
<div class="mb-6">
|
||||
<h3 class="text-lg font-semibold text-gray-700 dark:text-gray-200 mb-4">Change Password</h3>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label for="current_password" class="block text-gray-700 dark:text-gray-200 text-sm font-bold mb-2">Current Password</label>
|
||||
<input type="password" name="current_password" id="current_password"
|
||||
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 dark:text-gray-300 dark:bg-gray-700 leading-tight focus:outline-none focus:shadow-outline">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="new_password" class="block text-gray-700 dark:text-gray-200 text-sm font-bold mb-2">New Password</label>
|
||||
<input type="password" name="new_password" id="new_password"
|
||||
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 dark:text-gray-300 dark:bg-gray-700 leading-tight focus:outline-none focus:shadow-outline">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="new_password_confirmation" class="block text-gray-700 dark:text-gray-200 text-sm font-bold mb-2">Confirm New Password</label>
|
||||
<input type="password" name="new_password_confirmation" id="new_password_confirmation"
|
||||
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 dark:text-gray-300 dark:bg-gray-700 leading-tight focus:outline-none focus:shadow-outline">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<div class="flex justify-end">
|
||||
<button type="submit" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">
|
||||
Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function updatePreview(input) {
|
||||
const file = input.files[0];
|
||||
const preview = document.getElementById('preview');
|
||||
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
preview.src = e.target.result;
|
||||
}
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -301,21 +301,130 @@ class="fixed inset-y-0 left-0 w-full max-w-xs bg-white dark:bg-gray-800 overflow
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Firebase App (the core Firebase SDK) -->
|
||||
<script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-app.js"></script>
|
||||
<!-- Firebase Database -->
|
||||
<script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-database.js"></script>
|
||||
<!-- Firebase SDK v8 -->
|
||||
<script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js"></script>
|
||||
<script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-database.js"></script>
|
||||
|
||||
<script>
|
||||
// Your web app's Firebase configuration
|
||||
// Firebase configuration
|
||||
const firebaseConfig = {
|
||||
apiKey: "AIzaSyCr8xNQIsPpIUMGIR9wEGmG7hgMDKf2H5I",
|
||||
authDomain: "smartcab-8bb42.firebaseapp.com",
|
||||
databaseURL: "https://smartcab-8bb42-default-rtdb.firebaseio.com",
|
||||
projectId: "smartcab-8bb42",
|
||||
storageBucket: "smartcab-8bb42.firebasestorage.app",
|
||||
messagingSenderId: "539751617121",
|
||||
appId: "1:539751617121:web:3a899309fdb5e29efa9020",
|
||||
measurementId: "G-BQPQLLCJTR"
|
||||
};
|
||||
|
||||
// Initialize Firebase
|
||||
firebase.initializeApp(firebaseConfig);
|
||||
const database = firebase.database();
|
||||
|
||||
let isUserAction = false;
|
||||
|
||||
// Function to update UI elements
|
||||
function updateUIElement(elementId, value, suffix = '') {
|
||||
const element = document.getElementById(elementId);
|
||||
if (element) {
|
||||
element.textContent = `${value}${suffix}`;
|
||||
console.log(`Updated ${elementId} with value: ${value}${suffix}`);
|
||||
} else {
|
||||
console.error(`Element ${elementId} not found`);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to update UI with new data
|
||||
function updateUI(data) {
|
||||
console.log('Updating UI with data:', data);
|
||||
|
||||
if (data.dht11) {
|
||||
updateUIElement('temp-value', data.dht11.temperature, '°C');
|
||||
updateUIElement('humidity-value', data.dht11.humidity, '%');
|
||||
|
||||
// Update chart if it exists
|
||||
if (typeof sensorChart !== 'undefined') {
|
||||
updateChart(Date.now(), data.dht11.temperature, data.dht11.humidity);
|
||||
}
|
||||
}
|
||||
|
||||
if (data.security) {
|
||||
updateUIElement('motion-value', data.security.motion);
|
||||
updateUIElement('status-value', data.security.status);
|
||||
|
||||
const toggle = document.getElementById('securityToggle');
|
||||
if (toggle) {
|
||||
toggle.checked = data.security.status === 'on';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Function to fetch and update data
|
||||
function fetchAndUpdateData() {
|
||||
fetch('https://smartcab-8bb42-default-rtdb.firebaseio.com/.json')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log('Data fetched successfully:', data);
|
||||
updateUI(data);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Fetch error:', error);
|
||||
});
|
||||
}
|
||||
|
||||
// Function to toggle security status
|
||||
function toggleSecurity(checkbox) {
|
||||
isUserAction = true;
|
||||
console.log('Toggle security called with state:', checkbox.checked);
|
||||
|
||||
const securityRef = database.ref('security/status');
|
||||
const newStatus = checkbox.checked ? 'on' : 'off';
|
||||
|
||||
checkbox.disabled = true;
|
||||
|
||||
securityRef.set(newStatus)
|
||||
.then(() => {
|
||||
console.log('Security status updated successfully to:', newStatus);
|
||||
updateUIElement('status-value', newStatus);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error updating security status:', error);
|
||||
checkbox.checked = !checkbox.checked;
|
||||
alert('Failed to update security status. Please try again.');
|
||||
})
|
||||
.finally(() => {
|
||||
checkbox.disabled = false;
|
||||
setTimeout(() => {
|
||||
isUserAction = false;
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
// Listen for security status changes
|
||||
database.ref('security/status').on('value', (snapshot) => {
|
||||
const status = snapshot.val();
|
||||
if (status && !isUserAction) {
|
||||
console.log('Security status updated:', status);
|
||||
updateUIElement('status-value', status);
|
||||
|
||||
const securityToggle = document.getElementById('securityToggle');
|
||||
if (securityToggle && !securityToggle.disabled) {
|
||||
securityToggle.checked = status === 'on';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize when document is ready
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
console.log('Document ready, initializing...');
|
||||
fetchAndUpdateData();
|
||||
setInterval(fetchAndUpdateData, 1000);
|
||||
|
||||
// Initialize charts
|
||||
initializeCharts();
|
||||
});
|
||||
|
||||
// Initialize the chart with empty data
|
||||
const ctx = document.getElementById('sensorChart').getContext('2d');
|
||||
const sensorChart = new Chart(ctx, {
|
||||
|
@ -394,13 +503,6 @@ function updateChart(timestamp, temperature, humidity) {
|
|||
sensorChart.update();
|
||||
}
|
||||
|
||||
// Listen for real-time updates
|
||||
database.ref('dht11').on('value', (snapshot) => {
|
||||
const data = snapshot.val();
|
||||
const timestamp = Date.now();
|
||||
updateChart(timestamp, data.temperature, data.humidity);
|
||||
});
|
||||
|
||||
// Mobile Menu Toggle
|
||||
const mobileMenuBtn = document.getElementById('mobileMenuBtn');
|
||||
const mobileMenu = document.getElementById('mobileMenu');
|
||||
|
@ -556,29 +658,6 @@ function initializeCharts() {
|
|||
});
|
||||
}
|
||||
|
||||
initializeCharts();
|
||||
|
||||
// Real-time listeners for sensor data
|
||||
const dbRef = firebase.database();
|
||||
|
||||
// DHT11 Sensor listener
|
||||
dbRef.ref('dht11').on('value', (snapshot) => {
|
||||
const data = snapshot.val();
|
||||
if (data) {
|
||||
document.getElementById('temp-value').textContent = `${data.temperature}°C`;
|
||||
document.getElementById('humidity-value').textContent = `${data.humidity}%`;
|
||||
}
|
||||
});
|
||||
|
||||
// Security listener
|
||||
dbRef.ref('security').on('value', (snapshot) => {
|
||||
const data = snapshot.val();
|
||||
if (data) {
|
||||
document.getElementById('motion-value').textContent = data.motion;
|
||||
document.getElementById('status-value').textContent = data.status;
|
||||
}
|
||||
});
|
||||
|
||||
// Add these functions to your existing script
|
||||
function toggleModal() {
|
||||
const modal = document.getElementById('controlModal');
|
||||
|
@ -586,26 +665,12 @@ function toggleModal() {
|
|||
|
||||
// Update toggle state when modal opens
|
||||
if (!modal.classList.contains('hidden')) {
|
||||
dbRef.ref('security/status').once('value', (snapshot) => {
|
||||
database.ref('security/status').once('value', (snapshot) => {
|
||||
const status = snapshot.val();
|
||||
document.getElementById('securityToggle').checked = status === 'on';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function toggleSecurity(checkbox) {
|
||||
const newStatus = checkbox.checked ? 'on' : 'off';
|
||||
dbRef.ref('security').update({
|
||||
status: newStatus
|
||||
});
|
||||
}
|
||||
|
||||
// Listen for security status changes
|
||||
dbRef.ref('security/status').on('value', (snapshot) => {
|
||||
const status = snapshot.val();
|
||||
document.getElementById('securityToggle').checked = status === 'on';
|
||||
document.getElementById('status-value').textContent = status;
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
use App\Http\Controllers\Auth\FirebaseAuthController;
|
||||
use App\Http\Controllers\AIChatController;
|
||||
use App\Http\Controllers\WelcomeController;
|
||||
use App\Http\Controllers\ProfileController;
|
||||
|
||||
Route::get('/login', [FirebaseAuthController::class, 'showLogin'])
|
||||
->name('login')
|
||||
|
@ -30,3 +31,6 @@
|
|||
}
|
||||
return view('auth.login');
|
||||
});
|
||||
|
||||
Route::get('/profile', [ProfileController::class, 'index'])->name('profile');
|
||||
Route::post('/profile/update', [ProfileController::class, 'update'])->name('profile.update');
|
||||
|
|
Loading…
Reference in New Issue