feat-invite_staff #9

Merged
brontomark merged 5 commits from feat-invite_staff into main 2026-04-28 15:34:33 +02:00
8 changed files with 74 additions and 6 deletions
Showing only changes of commit 32c97accd7 - Show all commits

View File

@@ -40,9 +40,26 @@ class SessionCubit extends Cubit<SessionState> {
try { try {
// 1. CHI È QUESTO UTENTE? (Vediamo se ha un profilo staff, che sia Invitato o Admin) // 1. CHI È QUESTO UTENTE? (Vediamo se ha un profilo staff, che sia Invitato o Admin)
final staff = await _repository.getStaffMemberByUserId(user.id); StaffMemberModel? staff = await _repository.getStaffMemberByUserId(
// 1. Controllo Azienda user.id,
);
CompanyModel? company; CompanyModel? company;
if (staff != null) {
// --- LA MAGIA DEL SENSORE ---
if (staff.hasJoined == false) {
// È la primissima volta che entra! Aggiorniamo il DB.
await _repository.updateStaffMember(staff.id!, {'has_joined': true});
// Aggiorniamo anche il nostro modello in memoria per questa sessione
staff = staff.copyWith(hasJoined: true);
}
company = await _repository.getCompanyById(staff.companyId);
} else {
// È l'Admin in onboarding
company = await _repository.getCompanyByOwnerId(user.id);
}
// 1. Controllo Azienda
if (staff != null) { if (staff != null) {
// L'utente esiste già nel sistema! Carichiamo l'azienda per cui lavora // L'utente esiste già nel sistema! Carichiamo l'azienda per cui lavora
company = await _repository.getCompanyById(staff.companyId); company = await _repository.getCompanyById(staff.companyId);

View File

@@ -0,0 +1,2 @@
const String resetPasswordUrl =
'https://flux-web-invite.marco-6ba.workers.dev/';

View File

@@ -131,4 +131,11 @@ class CoreRepository {
'store_id': storeId, 'store_id': storeId,
}); });
} }
Future<void> updateStaffMember(
String staffId,
Map<String, dynamic> data,
) async {
await _supabase.from('staff_member').update(data).eq('id', staffId);
}
} }

View File

@@ -1,6 +1,7 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/core/data/constants.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
import 'package:supabase_flutter/supabase_flutter.dart'; import 'package:supabase_flutter/supabase_flutter.dart';
part 'auth_state.dart'; part 'auth_state.dart';
@@ -64,6 +65,28 @@ class AuthCubit extends Cubit<AuthState> {
} }
} }
Future<void> requestPasswordReset(String email) async {
if (email.isEmpty) {
emit(
state.copyWith(
status: AuthStatus.failure,
errorMessage: 'Devi inserire l\'indirizzo email',
),
);
return;
}
await _supabase.auth.resetPasswordForEmail(
email,
redirectTo: resetPasswordUrl,
);
emit(
state.copyWith(
status: AuthStatus.pwResetSent,
infoMessage: "Email per reset password inviata a $email!",
),
);
}
Future<void> requestLogout() async { Future<void> requestLogout() async {
await _supabase.auth.signOut(); await _supabase.auth.signOut();
emit(state.copyWith(status: AuthStatus.initial)); emit(state.copyWith(status: AuthStatus.initial));

View File

@@ -1,6 +1,6 @@
part of 'auth_cubit.dart'; part of 'auth_cubit.dart';
enum AuthStatus { initial, loading, failure } enum AuthStatus { initial, pwResetSent, loading, failure }
class AuthState extends Equatable { class AuthState extends Equatable {
final AuthStatus status; final AuthStatus status;

View File

@@ -162,6 +162,21 @@ class _AuthScreenState extends State<AuthScreen> {
), ),
), ),
), ),
if (state.isLoginMode) ...[
const SizedBox(height: 24),
TextButton(
onPressed: () => context
.read<AuthCubit>()
.requestPasswordReset(_emailController.text.trim()),
child: Text(
'Pw dimenticata/Invito scaduto?',
style: TextStyle(
color: context.accent,
fontWeight: FontWeight.bold,
),
),
),
],
], ],
), ),
), ),

View File

@@ -25,6 +25,7 @@ class StaffMemberModel extends Equatable {
final String? jobTitle; final String? jobTitle;
final SystemRole systemRole; final SystemRole systemRole;
final bool isActive; final bool isActive;
final bool hasJoined;
const StaffMemberModel({ const StaffMemberModel({
this.id, this.id,
@@ -36,6 +37,7 @@ class StaffMemberModel extends Equatable {
this.jobTitle, this.jobTitle,
this.systemRole = SystemRole.user, this.systemRole = SystemRole.user,
this.isActive = true, this.isActive = true,
this.hasJoined = false,
}); });
StaffMemberModel copyWith({ StaffMemberModel copyWith({
@@ -49,6 +51,7 @@ class StaffMemberModel extends Equatable {
String? jobTitle, String? jobTitle,
SystemRole? systemRole, SystemRole? systemRole,
bool? isActive, bool? isActive,
bool? hasJoined,
}) { }) {
return StaffMemberModel( return StaffMemberModel(
id: id ?? this.id, id: id ?? this.id,
@@ -60,6 +63,7 @@ class StaffMemberModel extends Equatable {
jobTitle: jobTitle ?? this.jobTitle, jobTitle: jobTitle ?? this.jobTitle,
systemRole: systemRole ?? this.systemRole, systemRole: systemRole ?? this.systemRole,
isActive: isActive ?? this.isActive, isActive: isActive ?? this.isActive,
hasJoined: hasJoined ?? this.hasJoined,
); );
} }
@@ -71,8 +75,6 @@ class StaffMemberModel extends Equatable {
email: '', email: '',
phoneNumber: '', phoneNumber: '',
jobTitle: '', jobTitle: '',
systemRole: SystemRole.user,
isActive: true,
); );
} }
@@ -87,6 +89,7 @@ class StaffMemberModel extends Equatable {
jobTitle: map['job_title'] as String?, jobTitle: map['job_title'] as String?,
systemRole: SystemRole.fromString(map['system_role']), systemRole: SystemRole.fromString(map['system_role']),
isActive: map['is_active'] ?? true, isActive: map['is_active'] ?? true,
hasJoined: map['has_joined'] ?? false,
); );
} }
@@ -101,6 +104,7 @@ class StaffMemberModel extends Equatable {
if (jobTitle != null) 'job_title': jobTitle, if (jobTitle != null) 'job_title': jobTitle,
'system_role': systemRole.name, // Trasforma SystemRole.admin in 'admin' 'system_role': systemRole.name, // Trasforma SystemRole.admin in 'admin'
'is_active': isActive, 'is_active': isActive,
'has_joined': hasJoined,
}; };
} }
@@ -115,5 +119,6 @@ class StaffMemberModel extends Equatable {
jobTitle, jobTitle,
systemRole, systemRole,
isActive, isActive,
hasJoined,
]; ];
} }

View File

@@ -174,7 +174,6 @@ class AttachmentsSection extends StatelessWidget {
); );
}, },
), ),
// --- PANNELLO AZIONI CONTESTUALI (LA MAGIA) --- // --- PANNELLO AZIONI CONTESTUALI (LA MAGIA) ---
// Appare SOLO se c'è almeno un file selezionato // Appare SOLO se c'è almeno un file selezionato
if (state.selectedFiles.isNotEmpty) if (state.selectedFiles.isNotEmpty)