Initialize project and update portal port configuration

Set default portal port to 8081, fix Dart build issue in cart screen, and update setup documentation.

Co-Authored-By: Oz <oz-agent@warp.dev>
This commit is contained in:
rbhat
2026-04-10 19:08:30 +05:30
commit 39a4f3283f
29 changed files with 1405 additions and 0 deletions

View File

@ -0,0 +1,47 @@
import 'dart:convert';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/services.dart';
class AppConfigService {
AppConfigService._();
static final AppConfigService instance = AppConfigService._();
bool _initialized = false;
Future<void> initialize() async {
if (_initialized) return;
final configRaw =
await rootBundle.loadString('assets/config/runtime_config.json');
final Map<String, dynamic> config = json.decode(configRaw);
await Firebase.initializeApp(
options: FirebaseOptions(
apiKey: _required(config, 'firebase_api_key'),
appId: _required(config, 'firebase_app_id'),
messagingSenderId: _required(config, 'firebase_messaging_sender_id'),
projectId: _required(config, 'firebase_project_id'),
authDomain: _required(config, 'firebase_auth_domain'),
storageBucket: _required(config, 'firebase_storage_bucket'),
measurementId: _optional(config, 'firebase_measurement_id'),
),
);
_initialized = true;
}
String _required(Map<String, dynamic> config, String key) {
final value = (config[key] ?? '').toString().trim();
if (value.isEmpty || value.startsWith('replace-with-')) {
throw StateError('Missing required runtime configuration: $key');
}
return value;
}
String? _optional(Map<String, dynamic> config, String key) {
final value = (config[key] ?? '').toString().trim();
return value.isEmpty ? null : value;
}
}

View File

@ -0,0 +1,48 @@
import 'package:firebase_auth/firebase_auth.dart';
class AuthService {
AuthService._();
static final AuthService instance = AuthService._();
final FirebaseAuth _auth = FirebaseAuth.instance;
Stream<User?> authStateChanges() => _auth.authStateChanges();
User? get currentUser => _auth.currentUser;
Future<UserCredential> signInWithEmailPassword({
required String email,
required String password,
}) {
return _auth.signInWithEmailAndPassword(email: email, password: password);
}
Future<UserCredential> registerWithEmailPassword({
required String email,
required String password,
}) {
return _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
}
Future<void> sendPasswordResetEmail(String email) {
return _auth.sendPasswordResetEmail(email: email);
}
Future<UserCredential> signInWithGoogle() {
final provider = GoogleAuthProvider();
provider.setCustomParameters({'prompt': 'select_account'});
return _auth.signInWithPopup(provider);
}
Future<UserCredential> signInWithGithub() {
final provider = GithubAuthProvider();
return _auth.signInWithPopup(provider);
}
Future<void> signOut() {
return _auth.signOut();
}
}

View File

@ -0,0 +1,43 @@
import 'package:flutter/foundation.dart';
import '../models/cart_item.dart';
import '../models/product.dart';
class CartService extends ChangeNotifier {
final List<CartItem> _items = [];
List<CartItem> get items => List.unmodifiable(_items);
int get totalItems => _items.fold(0, (sum, item) => sum + item.quantity);
double get totalPrice =>
_items.fold(0.0, (sum, item) => sum + item.lineTotal);
void addProduct(Product product) {
final index = _items.indexWhere((item) => item.product.id == product.id);
if (index == -1) {
_items.add(CartItem(product: product));
} else {
_items[index].quantity += 1;
}
notifyListeners();
}
void removeProduct(String productId) {
_items.removeWhere((item) => item.product.id == productId);
notifyListeners();
}
void updateQuantity(String productId, int quantity) {
if (quantity < 1) return;
final index = _items.indexWhere((item) => item.product.id == productId);
if (index == -1) return;
_items[index].quantity = quantity;
notifyListeners();
}
void clear() {
_items.clear();
notifyListeners();
}
}

View File

@ -0,0 +1,55 @@
import '../models/product.dart';
class ProductRepository {
static const List<Product> products = [
Product(
id: 'p1',
name: 'Minimalist Chair',
description: 'Ergonomic chair with breathable fabric and oak finish.',
imageUrl: 'https://picsum.photos/seed/chair/900/600',
price: 129.99,
),
Product(
id: 'p2',
name: 'Modern Table Lamp',
description: 'Warm ambient lighting with dimmable touch controls.',
imageUrl: 'https://picsum.photos/seed/lamp/900/600',
price: 59.50,
),
Product(
id: 'p3',
name: 'Noise-Cancel Headphones',
description: 'Wireless over-ear headphones with premium audio.',
imageUrl: 'https://picsum.photos/seed/headphones/900/600',
price: 219.00,
),
Product(
id: 'p4',
name: 'Smart Watch',
description: 'Fitness tracking, sleep monitoring, and message alerts.',
imageUrl: 'https://picsum.photos/seed/watch/900/600',
price: 179.90,
),
Product(
id: 'p5',
name: 'Travel Backpack',
description: 'Water-resistant backpack with dedicated laptop sleeve.',
imageUrl: 'https://picsum.photos/seed/backpack/900/600',
price: 89.00,
),
Product(
id: 'p6',
name: 'Mechanical Keyboard',
description: 'Hot-swappable switches and customizable RGB lighting.',
imageUrl: 'https://picsum.photos/seed/keyboard/900/600',
price: 149.00,
),
];
static Product? byId(String id) {
for (final product in products) {
if (product.id == id) return product;
}
return null;
}
}