Registration: availability and vision
parent
0c0bf431e2
commit
017cf363d4
|
@ -18,6 +18,8 @@ class Constants {
|
||||||
static const String dbFieldUsersYearBorn = 'born';
|
static const String dbFieldUsersYearBorn = 'born';
|
||||||
static const String dbFieldUsersSkills = 'skills';
|
static const String dbFieldUsersSkills = 'skills';
|
||||||
static const String dbFieldUsersSkillsSought = 'skills_sought';
|
static const String dbFieldUsersSkillsSought = 'skills_sought';
|
||||||
|
static const String dbFieldUsersAvailability = 'availability';
|
||||||
|
static const String dbFieldUsersVisions = 'visions';
|
||||||
|
|
||||||
static const String pathLanguagesJson = 'lib/assets/languages.json';
|
static const String pathLanguagesJson = 'lib/assets/languages.json';
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,3 +36,43 @@ enum SkillOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum VisionOption {
|
||||||
|
marketLeader,
|
||||||
|
sustainableBusiness,
|
||||||
|
innovativeProduct,
|
||||||
|
exitStrategy;
|
||||||
|
|
||||||
|
String get displayName {
|
||||||
|
switch (this) {
|
||||||
|
case VisionOption.marketLeader:
|
||||||
|
return 'Become market leader';
|
||||||
|
case VisionOption.sustainableBusiness:
|
||||||
|
return 'Build a sustainable and ethical business';
|
||||||
|
case VisionOption.innovativeProduct:
|
||||||
|
return "Develop an innovative product that improves people's lives";
|
||||||
|
case VisionOption.exitStrategy:
|
||||||
|
return 'Pursue an exit strategy through sale or IPO';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AvailabilityOption {
|
||||||
|
lessThan10Hours,
|
||||||
|
tenTo20Hours,
|
||||||
|
twentyTo40Hours,
|
||||||
|
fullTime;
|
||||||
|
|
||||||
|
String get displayName {
|
||||||
|
switch (this) {
|
||||||
|
case AvailabilityOption.lessThan10Hours:
|
||||||
|
return 'Less than 10 hours';
|
||||||
|
case AvailabilityOption.tenTo20Hours:
|
||||||
|
return 'Part time (10 - 20 hours)';
|
||||||
|
case AvailabilityOption.twentyTo40Hours:
|
||||||
|
return 'Part time (20 - 40 hours)';
|
||||||
|
case AvailabilityOption.fullTime:
|
||||||
|
return 'Full time (40 hours or more)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import '../helper.dart';
|
||||||
|
|
||||||
class ProfileCategoryForm<T> extends StatefulWidget {
|
class ProfileCategoryForm<T> extends StatefulWidget {
|
||||||
final String title;
|
final String title;
|
||||||
|
@ -66,7 +67,7 @@ class ProfileCategoryFormState<T> extends State<ProfileCategoryForm<T>> {
|
||||||
children: List.generate(widget.options.length, (index) {
|
children: List.generate(widget.options.length, (index) {
|
||||||
final option = widget.options[index];
|
final option = widget.options[index];
|
||||||
return ChoiceChip(
|
return ChoiceChip(
|
||||||
label: Text(_getDisplayText(option)),
|
label: Text(getDisplayText(option)),
|
||||||
selected: _selectedOptions.contains(option),
|
selected: _selectedOptions.contains(option),
|
||||||
onSelected: (selected) {
|
onSelected: (selected) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
@ -110,18 +111,6 @@ class ProfileCategoryFormState<T> extends State<ProfileCategoryForm<T>> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String _getDisplayText(dynamic option) {
|
|
||||||
// Check if the option is an enum and has a displayName property
|
|
||||||
if (option is Enum) {
|
|
||||||
final dynamicEnum = option as dynamic;
|
|
||||||
if (dynamicEnum.displayName != null) {
|
|
||||||
return dynamicEnum.displayName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Fallback to default toString if not an enum
|
|
||||||
return option.toString().split('.').last;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _showSnackBar(String message) {
|
void _showSnackBar(String message) {
|
||||||
if (!_isSnackBarVisible) {
|
if (!_isSnackBarVisible) {
|
||||||
_isSnackBarVisible = true;
|
_isSnackBarVisible = true;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
import 'package:cofounderella/pages/user_vision_page.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../../enumerations.dart';
|
import '../../enumerations.dart';
|
||||||
import '../../services/auth/auth_service.dart';
|
import '../../services/auth/auth_service.dart';
|
||||||
import '../../services/user_service.dart';
|
import '../../services/user_service.dart';
|
||||||
import '../pages/registration_complete_page.dart';
|
|
||||||
import 'profile_category_form.dart';
|
import 'profile_category_form.dart';
|
||||||
|
|
||||||
class SkillsForm extends StatelessWidget {
|
class SkillsForm extends StatelessWidget {
|
||||||
|
@ -62,8 +62,8 @@ class SkillsForm extends StatelessWidget {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
// TODO set following registration page HERE
|
// set following registration page HERE
|
||||||
builder: (context) => const RegistrationCompletePage(),
|
builder: (context) => MatchingForm(isRegProcess: isRegProcess),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else if (isRegProcess) {
|
} else if (isRegProcess) {
|
||||||
|
|
|
@ -29,6 +29,21 @@ String convertDecimalToDMS(double decimalValue) {
|
||||||
return '${degrees.abs()}° ${minutes.abs()}\' ${seconds.abs()}" $direction';
|
return '${degrees.abs()}° ${minutes.abs()}\' ${seconds.abs()}" $direction';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Get the displayName of our own Enumerations.
|
||||||
|
///
|
||||||
|
String getDisplayText(dynamic option) {
|
||||||
|
// Check if the option is an enum and has a displayName property
|
||||||
|
if (option is Enum) {
|
||||||
|
final dynamicEnum = option as dynamic;
|
||||||
|
if (dynamicEnum.displayName != null) {
|
||||||
|
return dynamicEnum.displayName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fallback to default toString if not an enum
|
||||||
|
return option.toString().split('.').last;
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Show a simple message dialog
|
/// Show a simple message dialog
|
||||||
///
|
///
|
||||||
|
|
|
@ -27,7 +27,7 @@ class RegistrationCompletePage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 80),
|
const SizedBox(height: 80),
|
||||||
const Text(
|
const Text(
|
||||||
"You can now use the app.",
|
"You can enjoy the app now.",
|
||||||
style: TextStyle(fontSize: 18),
|
style: TextStyle(fontSize: 18),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
|
|
@ -0,0 +1,171 @@
|
||||||
|
import "package:cloud_firestore/cloud_firestore.dart";
|
||||||
|
import "package:flutter/material.dart";
|
||||||
|
import "../constants.dart";
|
||||||
|
import "../enumerations.dart";
|
||||||
|
import "registration_complete_page.dart";
|
||||||
|
import "../services/auth/auth_service.dart";
|
||||||
|
|
||||||
|
class MatchingForm extends StatefulWidget {
|
||||||
|
const MatchingForm({super.key, required this.isRegProcess});
|
||||||
|
|
||||||
|
final bool isRegProcess;
|
||||||
|
|
||||||
|
@override
|
||||||
|
MatchingFormState createState() => MatchingFormState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class MatchingFormState extends State<MatchingForm> {
|
||||||
|
Map<VisionOption, bool> selectedVisionOptions = {
|
||||||
|
VisionOption.marketLeader: false,
|
||||||
|
VisionOption.sustainableBusiness: false,
|
||||||
|
VisionOption.innovativeProduct: false,
|
||||||
|
VisionOption.exitStrategy: false,
|
||||||
|
};
|
||||||
|
AvailabilityOption? availability;
|
||||||
|
|
||||||
|
// get instance of auth
|
||||||
|
final AuthService _authService = AuthService();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_loadDataFromFirebase();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _loadDataFromFirebase() async {
|
||||||
|
final userDoc = FirebaseFirestore.instance
|
||||||
|
.collection(Constants.dbCollectionUsers)
|
||||||
|
.doc(_authService.getCurrentUser()!.uid);
|
||||||
|
final snapshot = await userDoc.get();
|
||||||
|
|
||||||
|
if (snapshot.exists) {
|
||||||
|
final data = snapshot.data();
|
||||||
|
setState(() {
|
||||||
|
// Load Vision options
|
||||||
|
if (data?[Constants.dbFieldUsersVisions] != null) {
|
||||||
|
for (var option in VisionOption.values) {
|
||||||
|
selectedVisionOptions[option] = data?[Constants.dbFieldUsersVisions]
|
||||||
|
.contains(option.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Load Availability option
|
||||||
|
if (data?[Constants.dbFieldUsersAvailability] != null) {
|
||||||
|
availability = AvailabilityOption.values.firstWhere(
|
||||||
|
(e) => e.toString() == data?[Constants.dbFieldUsersAvailability],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _saveDataToFirebase() async {
|
||||||
|
final userDoc = FirebaseFirestore.instance
|
||||||
|
.collection(Constants.dbCollectionUsers)
|
||||||
|
.doc(_authService.getCurrentUser()!.uid);
|
||||||
|
|
||||||
|
await userDoc.set(
|
||||||
|
{
|
||||||
|
Constants.dbFieldUsersVisions: selectedVisionOptions.entries
|
||||||
|
.where((entry) => entry.value)
|
||||||
|
.map((entry) => entry.key.toString())
|
||||||
|
.toList(),
|
||||||
|
Constants.dbFieldUsersAvailability: availability?.toString(),
|
||||||
|
},
|
||||||
|
SetOptions(merge: true), // avoid overwriting existing data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isVisionSelected() {
|
||||||
|
return selectedVisionOptions.containsValue(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleSubmit() {
|
||||||
|
if (!isVisionSelected()) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
|
content: Text('Please choose at least one long-term vision.'),
|
||||||
|
));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (availability == null) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
|
content: Text('Please select an availability option.'),
|
||||||
|
));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_saveDataToFirebase();
|
||||||
|
// Handle the form submission logic here
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
// TODO set following registration page HERE
|
||||||
|
builder: (context) => const RegistrationCompletePage(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('Personal preferences'),
|
||||||
|
),
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'Vision and goals',
|
||||||
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
const Text('What is your long-term vision for a startup?'),
|
||||||
|
...VisionOption.values.map((option) {
|
||||||
|
return CheckboxListTile(
|
||||||
|
title: Text(option.displayName),
|
||||||
|
value: selectedVisionOptions[option],
|
||||||
|
controlAffinity: ListTileControlAffinity.platform,
|
||||||
|
onChanged: (bool? value) {
|
||||||
|
if (value != null) {
|
||||||
|
setState(() {
|
||||||
|
selectedVisionOptions[option] = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
const SizedBox(height: 40),
|
||||||
|
const Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
'Availability and commitment',
|
||||||
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Text(
|
||||||
|
'How much time can you devote to the startup each week?',
|
||||||
|
),
|
||||||
|
...AvailabilityOption.values.map((option) {
|
||||||
|
return RadioListTile(
|
||||||
|
title: Text(option.displayName),
|
||||||
|
value: option,
|
||||||
|
groupValue: availability,
|
||||||
|
onChanged: (AvailabilityOption? value) {
|
||||||
|
setState(() {
|
||||||
|
availability = value;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Center(
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: handleSubmit,
|
||||||
|
child: Text(widget.isRegProcess ? 'Save and continue' : 'Save'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue