Added Sectors of Interest and Save Button to AppBars.

master
Rafael 2024-06-20 22:47:54 +02:00
parent e79bfd5b7e
commit 87beb2dace
11 changed files with 340 additions and 82 deletions

View File

@ -54,6 +54,7 @@ class Constants {
static const String dbFieldUsersCorpCulture = 'corp_culture';
static const String dbFieldUsersCommunication = 'communication';
static const String dbFieldUsersRiskTolerance = 'risk_tolerance';
static const String dbFieldUsersSectors = 'sectors_of_interest';
static const String dbStoragePathProfiles = 'profile_images';

View File

@ -252,3 +252,98 @@ enum RiskTolerance {
);
}
}
enum SectorOption {
agriculture,
ai,
vr,
automotive,
bigdata,
blockchain,
cloud,
crypto,
cybersecurity,
education,
energy,
fashion,
finance,
food,
gaming,
healthcare,
home,
industry,
insurance,
iot,
legal,
ml,
media,
pharma,
retail,
robotics,
saas,
sports,
travel;
String get displayName {
switch (this) {
case SectorOption.agriculture:
return 'Agriculture';
case SectorOption.ai:
return 'Artificial Intelligence';
case SectorOption.vr:
return 'Augmented/Virtual Reality';
case SectorOption.automotive:
return 'Automotive';
case SectorOption.bigdata:
return 'Big Data';
case SectorOption.blockchain:
return 'Blockchain';
case SectorOption.cloud:
return 'Cloud Computing';
case SectorOption.crypto:
return 'Cryptocurrencies/Digital Assets';
case SectorOption.cybersecurity:
return 'Cybersecurity';
case SectorOption.education:
return 'Education';
case SectorOption.energy:
return 'Energy and Environment';
case SectorOption.fashion:
return 'Fashion and Lifestyle';
case SectorOption.finance:
return 'Finance';
case SectorOption.food:
return 'Food and Beverage';
case SectorOption.gaming:
return 'Gaming';
case SectorOption.healthcare:
return 'Healthcare';
case SectorOption.home:
return 'Home and Garden';
case SectorOption.industry:
return 'Industry';
case SectorOption.insurance:
return 'Insurance';
case SectorOption.iot:
return 'Internet of Things';
case SectorOption.legal:
return 'Legal and Compliance';
case SectorOption.ml:
return 'Machine Learning';
case SectorOption.media:
return 'Media and Entertainment';
case SectorOption.pharma:
return 'Pharma';
case SectorOption.retail:
return 'Retail';
case SectorOption.robotics:
return 'Robotics';
case SectorOption.saas:
return 'SaaS';
case SectorOption.sports:
return 'Sports and Fitness';
case SectorOption.travel:
return 'Travel';
}
}
}

View File

@ -151,6 +151,13 @@ class CultureValuesFormPageState extends State<CultureValuesFormPage> {
return Scaffold(
appBar: AppBar(
title: const Text('Personal preferences'),
actions: [
if (widget.isEditMode && !widget.isRegProcess)
IconButton(
onPressed: handleSubmit,
icon: const Icon(Icons.save),
)
],
),
body: Padding(
padding: const EdgeInsets.all(16.0),

View File

@ -25,7 +25,7 @@ class ProfileCategoryForm<T> extends StatefulWidget {
required this.onSave,
required this.preSelectedOptions,
this.saveButtonText,
this.hideSaveButton = false, // Initialize hideSaveButton parameter
this.hideSaveButton = false,
});
@override
@ -47,6 +47,13 @@ class ProfileCategoryFormState<T> extends State<ProfileCategoryForm<T>> {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: [
if (!widget.hideSaveButton)
IconButton(
onPressed: _saveButtonClicked,
icon: const Icon(Icons.save),
)
],
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
@ -70,9 +77,9 @@ class ProfileCategoryFormState<T> extends State<ProfileCategoryForm<T>> {
if (_selectedOptions.length < widget.maxSelections) {
_selectedOptions.add(option);
} else {
// Provide feedback that maximum selections reached
_showSnackBar(
'Maximum selections reached for ${widget.title}');
'Maximum selections reached for ${widget.title}',
);
}
} else {
_selectedOptions.remove(option);
@ -85,13 +92,7 @@ class ProfileCategoryFormState<T> extends State<ProfileCategoryForm<T>> {
const SizedBox(height: 16.0),
if (!widget.hideSaveButton)
ElevatedButton(
onPressed: () {
if (_selectedOptions.length >= widget.minSelections) {
widget.onSave(_selectedOptions);
} else {
_showSnackBar('No selection made for ${widget.title}');
}
},
onPressed: _saveButtonClicked,
child: Text(widget.saveButtonText ?? 'Save'),
),
],
@ -100,6 +101,14 @@ class ProfileCategoryFormState<T> extends State<ProfileCategoryForm<T>> {
);
}
void _saveButtonClicked() {
if (_selectedOptions.length >= widget.minSelections) {
widget.onSave(_selectedOptions);
} else {
_showSnackBar('No selection made for ${widget.title}');
}
}
void _showSnackBar(String message) {
if (!_isSnackBarVisible) {
_isSnackBarVisible = true;

View File

@ -129,6 +129,13 @@ class RisksFormPageState extends State<RisksFormPage> {
return Scaffold(
appBar: AppBar(
title: const Text('Personal preferences'),
actions: [
if (widget.isEditMode && !widget.isRegProcess)
IconButton(
onPressed: handleSubmit,
icon: const Icon(Icons.save),
)
],
),
body: Padding(
padding: const EdgeInsets.all(16.0),

View File

@ -0,0 +1,89 @@
import 'package:flutter/material.dart';
import '../../enumerations.dart';
import '../../services/auth/auth_service.dart';
import '../../services/user_service.dart';
import '../constants.dart';
import '../pages/user_vision_page.dart';
import 'profile_category_form.dart';
class SectorsForm extends StatelessWidget {
SectorsForm({
super.key,
required this.isRegProcess,
required this.isEditMode,
});
final AuthService _authService = AuthService();
final bool isRegProcess;
final bool isEditMode;
@override
Widget build(BuildContext context) {
return FutureBuilder<List<SectorOption>>(
future: UserService.getSectorsFromFirebase(
_authService.getCurrentUser()!.uid,
),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
List<SectorOption>? userSectors = snapshot.data;
int max = 10;
return ProfileCategoryForm(
title: 'Sectors of interest',
header: 'Sectors of interest',
description: 'Select up to $max sectors that match your interests.',
saveButtonText: isRegProcess ? 'Save and continue' : 'Save',
options: SectorOption.values.toList(), // Convert enum to list
minSelections: 1,
maxSelections: max,
preSelectedOptions: userSectors ?? [],
onSave: (selectedOptions) async {
// Handle saving selected options
bool success = await UserService.saveSectorsToFirebase(
selectedOptions.cast<SectorOption>(),
_authService.getCurrentUser()!.uid,
);
if (context.mounted) {
if (success) {
if (isRegProcess) {
Navigator.push(
context,
MaterialPageRoute(
// set following registration page HERE
builder: (context) => UserVisionPage(
isRegProcess: isRegProcess,
isEditMode: false,
),
),
);
} else {
if (isEditMode == true) {
// pass selectedOptions data back to caller
Navigator.pop(context, {
Constants.dbFieldUsersSectors: selectedOptions,
});
} else {
// Navigate back after saving
Navigator.pop(context);
}
}
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Failed to save sectors of interest.'),
),
);
}
}
},
);
}
},
);
}
}

View File

@ -3,8 +3,8 @@ import '../../enumerations.dart';
import '../../services/auth/auth_service.dart';
import '../../services/user_service.dart';
import '../constants.dart';
import '../pages/user_vision_page.dart';
import 'profile_category_form.dart';
import 'sectors_form.dart';
class SkillsForm extends StatelessWidget {
SkillsForm({
@ -14,7 +14,6 @@ class SkillsForm extends StatelessWidget {
required this.isEditMode,
});
// get instance of auth
final AuthService _authService = AuthService();
final bool isRegProcess;
@ -27,7 +26,7 @@ class SkillsForm extends StatelessWidget {
future: UserService.getSkillsFromFirebase(
skillsSought,
_authService.getCurrentUser()!.uid,
), // Fetch skills from Firebase
),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
// Show loading indicator while fetching data
@ -58,7 +57,7 @@ class SkillsForm extends StatelessWidget {
_authService.getCurrentUser()!.uid,
);
// Then navigate to another screen or perform any other action???
// Then navigate to another screen or perform any other action
if (context.mounted) {
if (success) {
if (isRegProcess && skillsSought) {
@ -66,7 +65,7 @@ class SkillsForm extends StatelessWidget {
context,
MaterialPageRoute(
// set following registration page HERE
builder: (context) => UserVisionPage(
builder: (context) => SectorsForm(
isRegProcess: isRegProcess,
isEditMode: false,
),

View File

@ -160,6 +160,12 @@ class EditProfilePageState extends State<EditProfilePage> {
return Scaffold(
appBar: AppBar(
title: const Text('Edit Profile'),
actions: [
IconButton(
onPressed: _saveProfile,
icon: const Icon(Icons.save),
)
],
),
body: Padding(
padding: const EdgeInsets.all(16.0),

View File

@ -149,6 +149,13 @@ class UserVisionPageState extends State<UserVisionPage> {
return Scaffold(
appBar: AppBar(
title: const Text('Personal preferences'),
actions: [
if (widget.isEditMode && !widget.isRegProcess)
IconButton(
onPressed: handleSubmit,
icon: const Icon(Icons.save),
)
],
),
body: Padding(
padding: const EdgeInsets.all(16.0),

View File

@ -10,17 +10,16 @@ class WelcomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Start now'),
),
body: Padding(
appBar: AppBar(title: const Text('Welcome to ${Constants.appTitle}'),),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const TextBold(
text: 'Welcome to ${Constants.appTitle}',
text: 'Connect with Potential Co-Founders Here',
fontSize: 24,
),
const SizedBox(height: 16),
@ -80,6 +79,7 @@ class WelcomePage extends StatelessWidget {
),
),
),
),
);
}
}

View File

@ -284,4 +284,42 @@ class UserService {
return false;
}
}
static Future<bool> saveSectorsToFirebase(
List<SectorOption> sectors, String userId) async {
try {
List<String> sectorStrings = sectors.map((x) => x.toString()).toList();
await FirebaseFirestore.instance
.collection(Constants.dbCollectionUsers)
.doc(userId)
.update({
Constants.dbFieldUsersSectors: sectorStrings,
});
return true;
} catch (e) {
return false;
}
}
static Future<List<SectorOption>> getSectorsFromFirebase(
String userId) async {
try {
DocumentSnapshot userDoc = await FirebaseFirestore.instance
.collection(Constants.dbCollectionUsers)
.doc(userId)
.get();
if (userDoc.exists && userDoc.data() != null) {
var data = userDoc.data() as Map<String, dynamic>;
List<dynamic> sectors = data[Constants.dbFieldUsersSectors] ?? [];
return sectors
.map((x) => SectorOption.values
.firstWhere((option) => option.toString() == x))
.toList();
} else {
return [];
}
} catch (e) {
throw Exception('Error fetching sectors from Firebase: $e');
}
}
}