mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-15 09:45:25 +00:00
Compare commits
2 Commits
SP-1717-FE
...
SP-1696-fe
Author | SHA1 | Date | |
---|---|---|---|
338d4f5737 | |||
2681c837f5 |
@ -1,3 +1,2 @@
|
|||||||
ENV_NAME=development
|
ENV_NAME=development
|
||||||
BASE_URL=https://syncrow-dev.azurewebsites.net
|
BASE_URL=https://syncrow-dev.azurewebsites.net
|
||||||
RTDB_URL=https://syncrow-dev-79446.asia-southeast1.firebasedatabase.app/
|
|
||||||
|
@ -1,3 +1,2 @@
|
|||||||
ENV_NAME=production
|
ENV_NAME=production
|
||||||
BASE_URL=https://syncrow-staging.azurewebsites.net
|
BASE_URL=https://syncrow-staging.azurewebsites.net
|
||||||
RTDB_URL=https://syncrow-prod-79446.asia-southeast1.firebasedatabase.app/
|
|
||||||
|
@ -1,3 +1,2 @@
|
|||||||
ENV_NAME=staging
|
ENV_NAME=staging
|
||||||
BASE_URL=https://syncrow-staging.azurewebsites.net
|
BASE_URL=https://syncrow-staging.azurewebsites.net
|
||||||
RTDB_URL=https://syncrow-staging-79446.asia-southeast1.firebasedatabase.app/
|
|
||||||
|
34
.vscode/launch.json
vendored
34
.vscode/launch.json
vendored
@ -1,9 +1,14 @@
|
|||||||
{
|
{
|
||||||
"configurations": [
|
"configurations": [
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
"name": "DEVELOPMENT",
|
"name": "DEVELOPMENT",
|
||||||
|
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
|
|
||||||
"type": "dart",
|
"type": "dart",
|
||||||
|
|
||||||
"args": [
|
"args": [
|
||||||
"-d",
|
"-d",
|
||||||
"chrome",
|
"chrome",
|
||||||
@ -11,14 +16,19 @@
|
|||||||
"3000",
|
"3000",
|
||||||
"-t",
|
"-t",
|
||||||
"lib/main_dev.dart",
|
"lib/main_dev.dart",
|
||||||
"--web-experimental-hot-reload"
|
"--web-experimental-hot-reload",
|
||||||
],
|
],
|
||||||
|
|
||||||
"flutterMode": "debug"
|
"flutterMode": "debug"
|
||||||
},
|
|
||||||
{
|
},{
|
||||||
|
|
||||||
"name": "STAGING",
|
"name": "STAGING",
|
||||||
|
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
|
|
||||||
"type": "dart",
|
"type": "dart",
|
||||||
|
|
||||||
"args": [
|
"args": [
|
||||||
"-d",
|
"-d",
|
||||||
"chrome",
|
"chrome",
|
||||||
@ -26,14 +36,19 @@
|
|||||||
"3000",
|
"3000",
|
||||||
"-t",
|
"-t",
|
||||||
"lib/main_staging.dart",
|
"lib/main_staging.dart",
|
||||||
"--web-experimental-hot-reload"
|
"--web-experimental-hot-reload",
|
||||||
],
|
],
|
||||||
|
|
||||||
"flutterMode": "debug"
|
"flutterMode": "debug"
|
||||||
},
|
|
||||||
{
|
},{
|
||||||
|
|
||||||
"name": "PRODUCTION",
|
"name": "PRODUCTION",
|
||||||
|
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
|
|
||||||
"type": "dart",
|
"type": "dart",
|
||||||
|
|
||||||
"args": [
|
"args": [
|
||||||
"-d",
|
"-d",
|
||||||
"chrome",
|
"chrome",
|
||||||
@ -41,9 +56,12 @@
|
|||||||
"3000",
|
"3000",
|
||||||
"-t",
|
"-t",
|
||||||
"lib/main.dart",
|
"lib/main.dart",
|
||||||
"--web-experimental-hot-reload"
|
"--web-experimental-hot-reload",
|
||||||
],
|
],
|
||||||
|
|
||||||
"flutterMode": "debug"
|
"flutterMode": "debug"
|
||||||
}
|
|
||||||
|
},
|
||||||
|
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -1 +1 @@
|
|||||||
{"flutter":{"platforms":{"android":{"default":{"projectId":"test2-8a3d2","appId":"1:427332280600:android:2bc36fbe82994a3e0c7e6d","fileOutput":"android/app/google-services.json"}},"ios":{"default":{"projectId":"test2-8a3d2","appId":"1:427332280600:ios:14346b200780dc760c7e6d","uploadDebugSymbols":true,"fileOutput":"ios/Runner/GoogleService-Info.plist"}},"macos":{"default":{"projectId":"test2-8a3d2","appId":"1:427332280600:ios:14346b200780dc760c7e6d","uploadDebugSymbols":true,"fileOutput":"macos/Runner/GoogleService-Info.plist"}},"dart":{"lib/firebase_options.dart":{"projectId":"syncrow-prod-79446","configurations":{"web":"1:255001682464:web:a03e2d6214c13101561245"}}}}}}
|
{"flutter":{"platforms":{"android":{"default":{"projectId":"test2-8a3d2","appId":"1:427332280600:android:2bc36fbe82994a3e0c7e6d","fileOutput":"android/app/google-services.json"}},"ios":{"default":{"projectId":"test2-8a3d2","appId":"1:427332280600:ios:14346b200780dc760c7e6d","uploadDebugSymbols":true,"fileOutput":"ios/Runner/GoogleService-Info.plist"}},"macos":{"default":{"projectId":"test2-8a3d2","appId":"1:427332280600:ios:14346b200780dc760c7e6d","uploadDebugSymbols":true,"fileOutput":"macos/Runner/GoogleService-Info.plist"}},"dart":{"lib/firebase_options.dart":{"projectId":"test2-8a3d2","configurations":{"android":"1:427332280600:android:2bc36fbe82994a3e0c7e6d","ios":"1:427332280600:ios:14346b200780dc760c7e6d","macos":"1:427332280600:ios:14346b200780dc760c7e6d","web":"1:427332280600:web:ad50516a87a35a1a0c7e6d","windows":"1:427332280600:web:f7a25537ccd5a7bd0c7e6d"}}}}}}
|
@ -1,16 +0,0 @@
|
|||||||
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
|
|
||||||
|
|
||||||
final class DefaultFirebaseOptions extends FirebaseOptions {
|
|
||||||
const DefaultFirebaseOptions({
|
|
||||||
required String databaseUrl,
|
|
||||||
}) : super(
|
|
||||||
apiKey: 'AIzaSyDgq5ywsnFVbbQO-Xz1Z4sR5bBcuiDaS9g',
|
|
||||||
appId: '1:255001682464:web:a03e2d6214c13101561245',
|
|
||||||
messagingSenderId: '255001682464',
|
|
||||||
projectId: 'syncrow-prod-79446',
|
|
||||||
authDomain: 'syncrow-prod-79446.firebaseapp.com',
|
|
||||||
storageBucket: 'syncrow-prod-79446.firebasestorage.app',
|
|
||||||
databaseURL: databaseUrl,
|
|
||||||
measurementId: 'G-1850Q89RMK',
|
|
||||||
);
|
|
||||||
}
|
|
93
lib/firebase_options_dev.dart
Normal file
93
lib/firebase_options_dev.dart
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// File generated by FlutterFire CLI.
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
|
||||||
|
import 'package:flutter/foundation.dart'
|
||||||
|
show defaultTargetPlatform, kIsWeb, TargetPlatform;
|
||||||
|
|
||||||
|
/// Default [FirebaseOptions] for use with your Firebase apps.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```dart
|
||||||
|
/// import 'firebase_options.dart';
|
||||||
|
/// // ...
|
||||||
|
/// await Firebase.initializeApp(
|
||||||
|
/// options: DefaultFirebaseOptions.currentPlatform,
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
class DefaultFirebaseOptionsDev {
|
||||||
|
static FirebaseOptions get currentPlatform {
|
||||||
|
if (kIsWeb) {
|
||||||
|
return web;
|
||||||
|
}
|
||||||
|
switch (defaultTargetPlatform) {
|
||||||
|
case TargetPlatform.android:
|
||||||
|
return android;
|
||||||
|
case TargetPlatform.iOS:
|
||||||
|
return ios;
|
||||||
|
case TargetPlatform.macOS:
|
||||||
|
return macos;
|
||||||
|
case TargetPlatform.windows:
|
||||||
|
return windows;
|
||||||
|
case TargetPlatform.linux:
|
||||||
|
throw UnsupportedError(
|
||||||
|
'DefaultFirebaseOptions have not been configured for linux - '
|
||||||
|
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw UnsupportedError(
|
||||||
|
'DefaultFirebaseOptions are not supported for this platform.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const FirebaseOptions web = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyCVEvKsJYzhWDFM-9Od68FE0nPpP933st0',
|
||||||
|
appId: '1:427332280600:web:ad50516a87a35a1a0c7e6d',
|
||||||
|
messagingSenderId: '427332280600',
|
||||||
|
projectId: 'test2-8a3d2',
|
||||||
|
authDomain: 'test2-8a3d2.firebaseapp.com',
|
||||||
|
databaseURL: 'https://test2-8a3d2-default-rtdb.firebaseio.com',
|
||||||
|
storageBucket: 'test2-8a3d2.firebasestorage.app',
|
||||||
|
measurementId: 'G-Z1RTTTV5H9',
|
||||||
|
);
|
||||||
|
|
||||||
|
static const FirebaseOptions android = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyA5qOErxdm0zJmoHIB0TixfebYEsNRpwV0',
|
||||||
|
appId: '1:427332280600:android:2bc36fbe82994a3e0c7e6d',
|
||||||
|
messagingSenderId: '427332280600',
|
||||||
|
projectId: 'test2-8a3d2',
|
||||||
|
databaseURL: 'https://test2-8a3d2-default-rtdb.firebaseio.com',
|
||||||
|
storageBucket: 'test2-8a3d2.firebasestorage.app',
|
||||||
|
);
|
||||||
|
|
||||||
|
static const FirebaseOptions ios = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyABnpH6yo2RRjtkp4PlvtK84hKwRm2DhBw',
|
||||||
|
appId: '1:427332280600:ios:14346b200780dc760c7e6d',
|
||||||
|
messagingSenderId: '427332280600',
|
||||||
|
projectId: 'test2-8a3d2',
|
||||||
|
databaseURL: 'https://test2-8a3d2-default-rtdb.firebaseio.com',
|
||||||
|
storageBucket: 'test2-8a3d2.firebasestorage.app',
|
||||||
|
iosBundleId: 'com.example.syncrowWeb',
|
||||||
|
);
|
||||||
|
|
||||||
|
static const FirebaseOptions macos = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyABnpH6yo2RRjtkp4PlvtK84hKwRm2DhBw',
|
||||||
|
appId: '1:427332280600:ios:14346b200780dc760c7e6d',
|
||||||
|
messagingSenderId: '427332280600',
|
||||||
|
projectId: 'test2-8a3d2',
|
||||||
|
databaseURL: 'https://test2-8a3d2-default-rtdb.firebaseio.com',
|
||||||
|
storageBucket: 'test2-8a3d2.firebasestorage.app',
|
||||||
|
iosBundleId: 'com.example.syncrowWeb',
|
||||||
|
);
|
||||||
|
|
||||||
|
static const FirebaseOptions windows = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyDizKjPC5rdkEjDxwXjM-RU5unB0Ziq3iw',
|
||||||
|
appId: '1:427332280600:web:f7a25537ccd5a7bd0c7e6d',
|
||||||
|
messagingSenderId: '427332280600',
|
||||||
|
projectId: 'test2-8a3d2',
|
||||||
|
authDomain: 'test2-8a3d2.firebaseapp.com',
|
||||||
|
databaseURL: 'https://test2-8a3d2-default-rtdb.firebaseio.com',
|
||||||
|
storageBucket: 'test2-8a3d2.firebasestorage.app',
|
||||||
|
measurementId: 'G-4LFVXEXWKY',
|
||||||
|
);
|
||||||
|
}
|
77
lib/firebase_options_prod.dart
Normal file
77
lib/firebase_options_prod.dart
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// File generated by FlutterFire CLI.
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
|
||||||
|
import 'package:flutter/foundation.dart' show defaultTargetPlatform, kIsWeb, TargetPlatform;
|
||||||
|
|
||||||
|
/// Default [FirebaseOptions] for use with your Firebase apps.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```dart
|
||||||
|
/// import 'firebase_options.dart';
|
||||||
|
/// // ...
|
||||||
|
/// await Firebase.initializeApp(
|
||||||
|
/// options: DefaultFirebaseOptions.currentPlatform,
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
class DefaultFirebaseOptionsStaging {
|
||||||
|
static FirebaseOptions get currentPlatform {
|
||||||
|
if (kIsWeb) {
|
||||||
|
return web;
|
||||||
|
}
|
||||||
|
switch (defaultTargetPlatform) {
|
||||||
|
case TargetPlatform.android:
|
||||||
|
return android;
|
||||||
|
case TargetPlatform.iOS:
|
||||||
|
return ios;
|
||||||
|
case TargetPlatform.macOS:
|
||||||
|
throw UnsupportedError(
|
||||||
|
'DefaultFirebaseOptions have not been configured for macos - '
|
||||||
|
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||||
|
);
|
||||||
|
case TargetPlatform.windows:
|
||||||
|
throw UnsupportedError(
|
||||||
|
'DefaultFirebaseOptions have not been configured for windows - '
|
||||||
|
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||||
|
);
|
||||||
|
case TargetPlatform.linux:
|
||||||
|
throw UnsupportedError(
|
||||||
|
'DefaultFirebaseOptions have not been configured for linux - '
|
||||||
|
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw UnsupportedError(
|
||||||
|
'DefaultFirebaseOptions are not supported for this platform.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const FirebaseOptions android = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyDP9GpYfLE8gHTj3kZ1hW8fx_FkJqOqSQk',
|
||||||
|
appId: '1:786692570726:android:0ef7079c2b978d4417b7a7',
|
||||||
|
messagingSenderId: '786692570726',
|
||||||
|
projectId: 'syncrow-staging',
|
||||||
|
databaseURL: 'https://syncrow-staging-default-rtdb.firebaseio.com',
|
||||||
|
storageBucket: 'syncrow-staging.appspot.com',
|
||||||
|
);
|
||||||
|
|
||||||
|
static const FirebaseOptions ios = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyAWlRiuJ75FMlf2_UDdri1voWKvkaSHtRg',
|
||||||
|
appId: '1:786692570726:ios:455a6fcff77e130f17b7a7',
|
||||||
|
messagingSenderId: '786692570726',
|
||||||
|
projectId: 'syncrow-staging',
|
||||||
|
databaseURL: 'https://syncrow-staging-default-rtdb.firebaseio.com',
|
||||||
|
storageBucket: 'syncrow-staging.appspot.com',
|
||||||
|
iosBundleId: 'com.example.syncrow.app',
|
||||||
|
);
|
||||||
|
|
||||||
|
static const FirebaseOptions web = FirebaseOptions(
|
||||||
|
apiKey: 'AIzaSyDyGaQ3sZhb4meaY6sGke-YglhdhJ2is8Q',
|
||||||
|
appId: '1:786692570726:web:93c931e6701797b317b7a7',
|
||||||
|
messagingSenderId: '786692570726',
|
||||||
|
projectId: 'syncrow-staging',
|
||||||
|
authDomain: 'syncrow-staging.firebaseapp.com',
|
||||||
|
databaseURL: 'https://syncrow-staging-default-rtdb.firebaseio.com',
|
||||||
|
storageBucket: 'syncrow-staging.appspot.com',
|
||||||
|
measurementId: 'G-CZ3J3G6LMQ',
|
||||||
|
);
|
||||||
|
}
|
@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:syncrow_web/firebase_options.dart';
|
import 'package:syncrow_web/firebase_options_prod.dart';
|
||||||
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||||
@ -27,9 +27,7 @@ Future<void> main() async {
|
|||||||
await dotenv.load(fileName: '.env.$environment');
|
await dotenv.load(fileName: '.env.$environment');
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
await Firebase.initializeApp(
|
await Firebase.initializeApp(
|
||||||
options: DefaultFirebaseOptions(
|
options: DefaultFirebaseOptionsStaging.currentPlatform,
|
||||||
databaseUrl: dotenv.env['RTDB_URL']!,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
initialSetup();
|
initialSetup();
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
@ -61,7 +59,7 @@ class MyApp extends StatelessWidget {
|
|||||||
BlocProvider<CreateRoutineBloc>(
|
BlocProvider<CreateRoutineBloc>(
|
||||||
create: (context) => CreateRoutineBloc(),
|
create: (context) => CreateRoutineBloc(),
|
||||||
),
|
),
|
||||||
BlocProvider(create: (context) => HomeBloc()..add(const FetchUserInfo())),
|
BlocProvider(create: (context) => HomeBloc()..add(FetchUserInfo())),
|
||||||
BlocProvider<VisitorPasswordBloc>(
|
BlocProvider<VisitorPasswordBloc>(
|
||||||
create: (context) => VisitorPasswordBloc(),
|
create: (context) => VisitorPasswordBloc(),
|
||||||
),
|
),
|
||||||
|
@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:syncrow_web/firebase_options.dart';
|
import 'package:syncrow_web/firebase_options_dev.dart';
|
||||||
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||||
@ -27,9 +27,7 @@ Future<void> main() async {
|
|||||||
await dotenv.load(fileName: '.env.$environment');
|
await dotenv.load(fileName: '.env.$environment');
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
await Firebase.initializeApp(
|
await Firebase.initializeApp(
|
||||||
options: DefaultFirebaseOptions(
|
options: DefaultFirebaseOptionsDev.currentPlatform,
|
||||||
databaseUrl: dotenv.env['RTDB_URL']!,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
initialSetup();
|
initialSetup();
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
@ -61,7 +59,7 @@ class MyApp extends StatelessWidget {
|
|||||||
BlocProvider<CreateRoutineBloc>(
|
BlocProvider<CreateRoutineBloc>(
|
||||||
create: (context) => CreateRoutineBloc(),
|
create: (context) => CreateRoutineBloc(),
|
||||||
),
|
),
|
||||||
BlocProvider(create: (context) => HomeBloc()..add(const FetchUserInfo())),
|
BlocProvider(create: (context) => HomeBloc()..add(FetchUserInfo())),
|
||||||
BlocProvider<VisitorPasswordBloc>(
|
BlocProvider<VisitorPasswordBloc>(
|
||||||
create: (context) => VisitorPasswordBloc(),
|
create: (context) => VisitorPasswordBloc(),
|
||||||
),
|
),
|
||||||
|
@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:syncrow_web/firebase_options.dart';
|
import 'package:syncrow_web/firebase_options_prod.dart';
|
||||||
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||||
@ -24,9 +24,7 @@ Future<void> main() async {
|
|||||||
await dotenv.load(fileName: '.env.$environment');
|
await dotenv.load(fileName: '.env.$environment');
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
await Firebase.initializeApp(
|
await Firebase.initializeApp(
|
||||||
options: DefaultFirebaseOptions(
|
options: DefaultFirebaseOptionsStaging.currentPlatform,
|
||||||
databaseUrl: dotenv.env['RTDB_URL']!,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
initialSetup();
|
initialSetup();
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
@ -58,7 +56,7 @@ class MyApp extends StatelessWidget {
|
|||||||
BlocProvider<CreateRoutineBloc>(
|
BlocProvider<CreateRoutineBloc>(
|
||||||
create: (context) => CreateRoutineBloc(),
|
create: (context) => CreateRoutineBloc(),
|
||||||
),
|
),
|
||||||
BlocProvider(create: (context) => HomeBloc()..add(const FetchUserInfo())),
|
BlocProvider(create: (context) => HomeBloc()..add(FetchUserInfo())),
|
||||||
BlocProvider<VisitorPasswordBloc>(
|
BlocProvider<VisitorPasswordBloc>(
|
||||||
create: (context) => VisitorPasswordBloc(),
|
create: (context) => VisitorPasswordBloc(),
|
||||||
),
|
),
|
||||||
|
@ -153,6 +153,7 @@ class EditUserModel {
|
|||||||
final String? jobTitle; // can be empty
|
final String? jobTitle; // can be empty
|
||||||
final String roleType; // e.g. "ADMIN"
|
final String roleType; // e.g. "ADMIN"
|
||||||
final List<UserSpaceModel> spaces;
|
final List<UserSpaceModel> spaces;
|
||||||
|
final String? companyName;
|
||||||
|
|
||||||
EditUserModel({
|
EditUserModel({
|
||||||
required this.uuid,
|
required this.uuid,
|
||||||
@ -167,6 +168,7 @@ class EditUserModel {
|
|||||||
required this.jobTitle,
|
required this.jobTitle,
|
||||||
required this.roleType,
|
required this.roleType,
|
||||||
required this.spaces,
|
required this.spaces,
|
||||||
|
this.companyName,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Create a [UserData] from JSON data
|
/// Create a [UserData] from JSON data
|
||||||
@ -182,6 +184,7 @@ class EditUserModel {
|
|||||||
invitedBy: json['invitedBy'] as String,
|
invitedBy: json['invitedBy'] as String,
|
||||||
phoneNumber: json['phoneNumber'] ?? '',
|
phoneNumber: json['phoneNumber'] ?? '',
|
||||||
jobTitle: json['jobTitle'] ?? '',
|
jobTitle: json['jobTitle'] ?? '',
|
||||||
|
companyName: json['companyName'] as String?,
|
||||||
roleType: json['roleType'] as String,
|
roleType: json['roleType'] as String,
|
||||||
spaces: (json['spaces'] as List<dynamic>)
|
spaces: (json['spaces'] as List<dynamic>)
|
||||||
.map((e) => UserSpaceModel.fromJson(e as Map<String, dynamic>))
|
.map((e) => UserSpaceModel.fromJson(e as Map<String, dynamic>))
|
||||||
|
@ -12,7 +12,7 @@ class RolesUserModel {
|
|||||||
final dynamic jobTitle;
|
final dynamic jobTitle;
|
||||||
final dynamic createdDate;
|
final dynamic createdDate;
|
||||||
final dynamic createdTime;
|
final dynamic createdTime;
|
||||||
|
final String? companyName;
|
||||||
RolesUserModel({
|
RolesUserModel({
|
||||||
required this.uuid,
|
required this.uuid,
|
||||||
required this.createdAt,
|
required this.createdAt,
|
||||||
@ -27,6 +27,7 @@ class RolesUserModel {
|
|||||||
this.jobTitle,
|
this.jobTitle,
|
||||||
required this.createdDate,
|
required this.createdDate,
|
||||||
required this.createdTime,
|
required this.createdTime,
|
||||||
|
this.companyName,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory RolesUserModel.fromJson(Map<String, dynamic> json) {
|
factory RolesUserModel.fromJson(Map<String, dynamic> json) {
|
||||||
@ -47,6 +48,7 @@ class RolesUserModel {
|
|||||||
: json['jobTitle'],
|
: json['jobTitle'],
|
||||||
createdDate: json['createdDate'],
|
createdDate: json['createdDate'],
|
||||||
createdTime: json['createdTime'],
|
createdTime: json['createdTime'],
|
||||||
|
companyName: json['companyName'] as String?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
final TextEditingController lastNameController = TextEditingController();
|
final TextEditingController lastNameController = TextEditingController();
|
||||||
final TextEditingController emailController = TextEditingController();
|
final TextEditingController emailController = TextEditingController();
|
||||||
final TextEditingController phoneController = TextEditingController();
|
final TextEditingController phoneController = TextEditingController();
|
||||||
final TextEditingController jobTitleController = TextEditingController();
|
final TextEditingController companyNameController = TextEditingController();
|
||||||
final TextEditingController roleSearchController = TextEditingController();
|
final TextEditingController roleSearchController = TextEditingController();
|
||||||
|
|
||||||
bool? isCompleteBasics;
|
bool? isCompleteBasics;
|
||||||
@ -352,7 +352,7 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
bool res = await UserPermissionApi().sendInviteUser(
|
bool res = await UserPermissionApi().sendInviteUser(
|
||||||
email: emailController.text,
|
email: emailController.text,
|
||||||
firstName: firstNameController.text,
|
firstName: firstNameController.text,
|
||||||
jobTitle: jobTitleController.text,
|
companyName: companyNameController.text,
|
||||||
lastName: lastNameController.text,
|
lastName: lastNameController.text,
|
||||||
phoneNumber: phoneController.text,
|
phoneNumber: phoneController.text,
|
||||||
roleUuid: roleSelected,
|
roleUuid: roleSelected,
|
||||||
@ -405,7 +405,7 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
bool res = await UserPermissionApi().editInviteUser(
|
bool res = await UserPermissionApi().editInviteUser(
|
||||||
userId: event.userId,
|
userId: event.userId,
|
||||||
firstName: firstNameController.text,
|
firstName: firstNameController.text,
|
||||||
jobTitle: jobTitleController.text,
|
companyName: companyNameController.text,
|
||||||
lastName: lastNameController.text,
|
lastName: lastNameController.text,
|
||||||
phoneNumber: phoneController.text,
|
phoneNumber: phoneController.text,
|
||||||
roleUuid: roleSelected,
|
roleUuid: roleSelected,
|
||||||
@ -529,7 +529,7 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
lastNameController.text = res.lastName;
|
lastNameController.text = res.lastName;
|
||||||
emailController.text = res.email;
|
emailController.text = res.email;
|
||||||
phoneController.text = res.phoneNumber ?? '';
|
phoneController.text = res.phoneNumber ?? '';
|
||||||
jobTitleController.text = res.jobTitle ?? '';
|
companyNameController.text = res.companyName ?? '';
|
||||||
res.roleType;
|
res.roleType;
|
||||||
res.spaces.map((space) {
|
res.spaces.map((space) {
|
||||||
selectedIds.add(space.uuid);
|
selectedIds.add(space.uuid);
|
||||||
@ -645,7 +645,7 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
lastNameController.dispose();
|
lastNameController.dispose();
|
||||||
emailController.dispose();
|
emailController.dispose();
|
||||||
phoneController.dispose();
|
phoneController.dispose();
|
||||||
jobTitleController.dispose();
|
companyNameController.dispose();
|
||||||
roleSearchController.dispose();
|
roleSearchController.dispose();
|
||||||
return super.close();
|
return super.close();
|
||||||
}
|
}
|
||||||
|
@ -317,7 +317,7 @@ class BasicsView extends StatelessWidget {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Job Title',
|
'Company Name',
|
||||||
style: context.textTheme.bodyMedium?.copyWith(
|
style: context.textTheme.bodyMedium?.copyWith(
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
@ -328,11 +328,11 @@ class BasicsView extends StatelessWidget {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: _blocRole.jobTitleController,
|
controller: _blocRole.companyNameController,
|
||||||
style:
|
style:
|
||||||
const TextStyle(color: ColorsManager.blackColor),
|
const TextStyle(color: ColorsManager.blackColor),
|
||||||
decoration: inputTextFormDeco(
|
decoration: inputTextFormDeco(
|
||||||
hintText: "Job Title (Optional)")
|
hintText: 'Company Name (Optional)')
|
||||||
.copyWith(
|
.copyWith(
|
||||||
hintStyle: context.textTheme.bodyMedium?.copyWith(
|
hintStyle: context.textTheme.bodyMedium?.copyWith(
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
|
@ -411,7 +411,7 @@ class UsersPage extends StatelessWidget {
|
|||||||
titles: const [
|
titles: const [
|
||||||
"Full Name",
|
"Full Name",
|
||||||
"Email Address",
|
"Email Address",
|
||||||
"Job Title",
|
"Company Name",
|
||||||
"Role",
|
"Role",
|
||||||
"Creation Date",
|
"Creation Date",
|
||||||
"Creation Time",
|
"Creation Time",
|
||||||
@ -424,7 +424,7 @@ class UsersPage extends StatelessWidget {
|
|||||||
return [
|
return [
|
||||||
Text('${user.firstName} ${user.lastName}'),
|
Text('${user.firstName} ${user.lastName}'),
|
||||||
Text(user.email),
|
Text(user.email),
|
||||||
Text(user.jobTitle),
|
Center(child: Text(user.companyName ?? '-')),
|
||||||
Text(user.roleType ?? ''),
|
Text(user.roleType ?? ''),
|
||||||
Text(user.createdDate ?? ''),
|
Text(user.createdDate ?? ''),
|
||||||
Text(user.createdTime ?? ''),
|
Text(user.createdTime ?? ''),
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
|
||||||
|
|
||||||
class SpaceReorderDataModel {
|
|
||||||
const SpaceReorderDataModel({
|
|
||||||
required this.space,
|
|
||||||
this.parent,
|
|
||||||
this.community,
|
|
||||||
});
|
|
||||||
|
|
||||||
final SpaceModel space;
|
|
||||||
final SpaceModel? parent;
|
|
||||||
final CommunityModel? community;
|
|
||||||
}
|
|
@ -16,37 +16,21 @@ import 'package:syncrow_web/services/api/http_service.dart';
|
|||||||
import 'package:syncrow_web/utils/theme/responsive_text_theme.dart';
|
import 'package:syncrow_web/utils/theme/responsive_text_theme.dart';
|
||||||
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||||
|
|
||||||
class SpaceManagementPage extends StatefulWidget {
|
class SpaceManagementPage extends StatelessWidget {
|
||||||
const SpaceManagementPage({super.key});
|
const SpaceManagementPage({super.key});
|
||||||
|
|
||||||
@override
|
|
||||||
State<SpaceManagementPage> createState() => _SpaceManagementPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SpaceManagementPageState extends State<SpaceManagementPage> {
|
|
||||||
late final CommunitiesBloc communitiesBloc;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
communitiesBloc = CommunitiesBloc(
|
|
||||||
communitiesService: DebouncedCommunitiesService(
|
|
||||||
RemoteCommunitiesService(HTTPService()),
|
|
||||||
),
|
|
||||||
)..add(const LoadCommunities(LoadCommunitiesParam()));
|
|
||||||
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MultiBlocProvider(
|
return MultiBlocProvider(
|
||||||
providers: [
|
providers: [
|
||||||
BlocProvider.value(value: communitiesBloc),
|
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
create: (context) => CommunitiesTreeSelectionBloc(
|
create: (context) => CommunitiesBloc(
|
||||||
communitiesBloc: communitiesBloc,
|
communitiesService: DebouncedCommunitiesService(
|
||||||
|
RemoteCommunitiesService(HTTPService()),
|
||||||
),
|
),
|
||||||
|
)..add(const LoadCommunities(LoadCommunitiesParam())),
|
||||||
),
|
),
|
||||||
|
BlocProvider(create: (context) => CommunitiesTreeSelectionBloc()),
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
create: (context) => SpaceDetailsBloc(
|
create: (context) => SpaceDetailsBloc(
|
||||||
UniqueSubspacesDecorator(
|
UniqueSubspacesDecorator(
|
||||||
|
@ -1,17 +1,13 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/models/space_connection_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/main_module/models/space_connection_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/models/space_reorder_data_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/painters/spaces_connections_arrow_painter.dart';
|
import 'package:syncrow_web/pages/space_management_v2/main_module/painters/spaces_connections_arrow_painter.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/create_space_button.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/space_card_widget.dart';
|
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/space_card_widget.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/space_cell.dart';
|
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/space_cell.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/bloc/communities_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/helpers/space_details_dialog_helper.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/helpers/space_details_dialog_helper.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
||||||
|
|
||||||
class CommunityStructureCanvas extends StatefulWidget {
|
class CommunityStructureCanvas extends StatefulWidget {
|
||||||
const CommunityStructureCanvas({
|
const CommunityStructureCanvas({
|
||||||
@ -35,9 +31,8 @@ class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
|
|||||||
final double _horizontalSpacing = 150.0;
|
final double _horizontalSpacing = 150.0;
|
||||||
final double _verticalSpacing = 120.0;
|
final double _verticalSpacing = 120.0;
|
||||||
|
|
||||||
late final TransformationController _transformationController;
|
late TransformationController _transformationController;
|
||||||
late final AnimationController _animationController;
|
late AnimationController _animationController;
|
||||||
SpaceReorderDataModel? _draggedData;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -102,7 +97,7 @@ class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
|
|||||||
final position = _positions[space.uuid];
|
final position = _positions[space.uuid];
|
||||||
if (position == null) return;
|
if (position == null) return;
|
||||||
|
|
||||||
const scale = 1;
|
const scale = 1.5;
|
||||||
final viewSize = context.size;
|
final viewSize = context.size;
|
||||||
if (viewSize == null) return;
|
if (viewSize == null) return;
|
||||||
|
|
||||||
@ -117,33 +112,16 @@ class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
|
|||||||
_runAnimation(matrix);
|
_runAnimation(matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onReorder(SpaceReorderDataModel data, int newIndex) {
|
|
||||||
final newCommunity = widget.community.copyWith();
|
|
||||||
final children = data.parent?.children ?? newCommunity.spaces;
|
|
||||||
final oldIndex = children.indexWhere((s) => s.uuid == data.space.uuid);
|
|
||||||
if (oldIndex != -1) {
|
|
||||||
final item = children.removeAt(oldIndex);
|
|
||||||
if (newIndex > oldIndex) {
|
|
||||||
children.insert(newIndex - 1, item);
|
|
||||||
} else {
|
|
||||||
children.insert(newIndex, item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
context.read<CommunitiesBloc>().add(
|
|
||||||
CommunitiesUpdateCommunity(newCommunity),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onSpaceTapped(SpaceModel? space) {
|
void _onSpaceTapped(SpaceModel? space) {
|
||||||
context.read<CommunitiesTreeSelectionBloc>().add(
|
context.read<CommunitiesTreeSelectionBloc>().add(
|
||||||
SelectSpaceEvent(community: widget.community, space: space),
|
SelectSpaceEvent(community: widget.community, space: space),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _resetSelectionAndZoom([CommunityModel? community]) {
|
void _resetSelectionAndZoom() {
|
||||||
context.read<CommunitiesTreeSelectionBloc>().add(
|
context.read<CommunitiesTreeSelectionBloc>().add(
|
||||||
SelectSpaceEvent(
|
SelectSpaceEvent(
|
||||||
community: community ?? widget.community,
|
community: widget.community,
|
||||||
space: null,
|
space: null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -204,8 +182,7 @@ class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
|
|||||||
_positions.clear();
|
_positions.clear();
|
||||||
final community = widget.community;
|
final community = widget.community;
|
||||||
|
|
||||||
final levelXOffset = <int, double>{};
|
_calculateLayout(community.spaces, 0, {});
|
||||||
_calculateLayout(community.spaces, 0, levelXOffset);
|
|
||||||
|
|
||||||
final selectedSpace = widget.selectedSpace;
|
final selectedSpace = widget.selectedSpace;
|
||||||
final highlightedUuids = <String>{};
|
final highlightedUuids = <String>{};
|
||||||
@ -216,24 +193,7 @@ class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
|
|||||||
|
|
||||||
final widgets = <Widget>[];
|
final widgets = <Widget>[];
|
||||||
final connections = <SpaceConnectionModel>[];
|
final connections = <SpaceConnectionModel>[];
|
||||||
_generateWidgets(
|
_generateWidgets(community.spaces, widgets, connections, highlightedUuids);
|
||||||
widget.community.spaces,
|
|
||||||
widgets,
|
|
||||||
connections,
|
|
||||||
highlightedUuids,
|
|
||||||
community: widget.community,
|
|
||||||
);
|
|
||||||
|
|
||||||
final createButtonX = levelXOffset[0] ?? 0.0;
|
|
||||||
const createButtonY = 0.0;
|
|
||||||
|
|
||||||
widgets.add(
|
|
||||||
Positioned(
|
|
||||||
left: createButtonX,
|
|
||||||
top: createButtonY,
|
|
||||||
child: CreateSpaceButton(communityUuid: widget.community.uuid),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
CustomPaint(
|
CustomPaint(
|
||||||
@ -251,30 +211,22 @@ class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
|
|||||||
List<SpaceModel> spaces,
|
List<SpaceModel> spaces,
|
||||||
List<Widget> widgets,
|
List<Widget> widgets,
|
||||||
List<SpaceConnectionModel> connections,
|
List<SpaceConnectionModel> connections,
|
||||||
Set<String> highlightedUuids, {
|
Set<String> highlightedUuids,
|
||||||
CommunityModel? community,
|
) {
|
||||||
SpaceModel? parent,
|
for (final space in spaces) {
|
||||||
}) {
|
|
||||||
if (spaces.isNotEmpty) {
|
|
||||||
final firstChildPos = _positions[spaces.first.uuid]!;
|
|
||||||
final targetPos = Offset(
|
|
||||||
firstChildPos.dx - (_horizontalSpacing / 4),
|
|
||||||
firstChildPos.dy,
|
|
||||||
);
|
|
||||||
widgets.add(_buildDropTarget(parent, community, 0, targetPos));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < spaces.length; i++) {
|
|
||||||
final space = spaces[i];
|
|
||||||
final position = _positions[space.uuid];
|
final position = _positions[space.uuid];
|
||||||
if (position == null) {
|
if (position == null) continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
final isHighlighted = highlightedUuids.contains(space.uuid);
|
final isHighlighted = highlightedUuids.contains(space.uuid);
|
||||||
final hasNoSelectedSpace = widget.selectedSpace == null;
|
final hasNoSelectedSpace = widget.selectedSpace == null;
|
||||||
|
|
||||||
final spaceCard = SpaceCardWidget(
|
widgets.add(
|
||||||
|
Positioned(
|
||||||
|
left: position.dx,
|
||||||
|
top: position.dy,
|
||||||
|
width: _cardWidth,
|
||||||
|
height: _cardHeight,
|
||||||
|
child: SpaceCardWidget(
|
||||||
buildSpaceContainer: () {
|
buildSpaceContainer: () {
|
||||||
return Opacity(
|
return Opacity(
|
||||||
opacity: hasNoSelectedSpace || isHighlighted ? 1.0 : 0.5,
|
opacity: hasNoSelectedSpace || isHighlighted ? 1.0 : 0.5,
|
||||||
@ -289,140 +241,28 @@ class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onTap: () => SpaceDetailsDialogHelper.showCreate(
|
onTap: () => SpaceDetailsDialogHelper.showCreate(context),
|
||||||
context,
|
|
||||||
communityUuid: widget.community.uuid,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
final reorderData = SpaceReorderDataModel(
|
|
||||||
space: space,
|
|
||||||
parent: parent,
|
|
||||||
community: community,
|
|
||||||
);
|
|
||||||
|
|
||||||
widgets.add(
|
|
||||||
Positioned(
|
|
||||||
left: position.dx,
|
|
||||||
top: position.dy,
|
|
||||||
width: _cardWidth,
|
|
||||||
height: _cardHeight,
|
|
||||||
child: Draggable<SpaceReorderDataModel>(
|
|
||||||
data: reorderData,
|
|
||||||
feedback: Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: Opacity(
|
|
||||||
opacity: 0.2,
|
|
||||||
child: SizedBox(
|
|
||||||
width: _cardWidth,
|
|
||||||
height: _cardHeight,
|
|
||||||
child: spaceCard,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onDragStarted: () => setState(() => _draggedData = reorderData),
|
|
||||||
onDragEnd: (_) => setState(() => _draggedData = null),
|
|
||||||
onDraggableCanceled: (_, __) => setState(() => _draggedData = null),
|
|
||||||
childWhenDragging: Opacity(opacity: 0.4, child: spaceCard),
|
|
||||||
child: spaceCard,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final targetPos = Offset(
|
|
||||||
position.dx + _cardWidth + (_horizontalSpacing / 4) - 20,
|
|
||||||
position.dy,
|
|
||||||
);
|
|
||||||
widgets.add(_buildDropTarget(parent, community, i + 1, targetPos));
|
|
||||||
|
|
||||||
for (final child in space.children) {
|
for (final child in space.children) {
|
||||||
connections.add(SpaceConnectionModel(from: space.uuid, to: child.uuid));
|
connections.add(
|
||||||
}
|
SpaceConnectionModel(from: space.uuid, to: child.uuid),
|
||||||
|
|
||||||
if (space.children.isNotEmpty) {
|
|
||||||
_generateWidgets(
|
|
||||||
space.children,
|
|
||||||
widgets,
|
|
||||||
connections,
|
|
||||||
highlightedUuids,
|
|
||||||
parent: space,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
_generateWidgets(space.children, widgets, connections, highlightedUuids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildDropTarget(
|
|
||||||
SpaceModel? parent,
|
|
||||||
CommunityModel? community,
|
|
||||||
int index,
|
|
||||||
Offset position,
|
|
||||||
) {
|
|
||||||
return Positioned(
|
|
||||||
left: position.dx,
|
|
||||||
top: position.dy,
|
|
||||||
width: 40,
|
|
||||||
height: _cardHeight,
|
|
||||||
child: DragTarget<SpaceReorderDataModel>(
|
|
||||||
builder: (context, candidateData, rejectedData) {
|
|
||||||
if (_draggedData == null) {
|
|
||||||
return const SizedBox();
|
|
||||||
}
|
|
||||||
|
|
||||||
final isTargetForDragged = (_draggedData?.parent?.uuid == parent?.uuid &&
|
|
||||||
_draggedData?.community == null) ||
|
|
||||||
(_draggedData?.community?.uuid == community?.uuid &&
|
|
||||||
_draggedData?.parent == null);
|
|
||||||
|
|
||||||
if (!isTargetForDragged) {
|
|
||||||
return const SizedBox();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Container(
|
|
||||||
width: 40,
|
|
||||||
height: _cardHeight,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: context.theme.colorScheme.primary.withValues(
|
|
||||||
alpha: candidateData.isNotEmpty ? 0.7 : 0.3,
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
child: Icon(
|
|
||||||
Icons.add,
|
|
||||||
color: context.theme.colorScheme.onPrimary,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onWillAcceptWithDetails: (data) {
|
|
||||||
final children = parent?.children ?? community?.spaces ?? [];
|
|
||||||
final isSameParent = (data.data.parent?.uuid == parent?.uuid &&
|
|
||||||
data.data.community == null) ||
|
|
||||||
(data.data.community?.uuid == community?.uuid &&
|
|
||||||
data.data.parent == null);
|
|
||||||
|
|
||||||
if (!isSameParent) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final oldIndex =
|
|
||||||
children.indexWhere((s) => s.uuid == data.data.space.uuid);
|
|
||||||
if (oldIndex == index || oldIndex == index - 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
onAcceptWithDetails: (data) => _onReorder(data.data, index),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final treeWidgets = _buildTreeWidgets();
|
final treeWidgets = _buildTreeWidgets();
|
||||||
return InteractiveViewer(
|
return InteractiveViewer(
|
||||||
transformationController: _transformationController,
|
transformationController: _transformationController,
|
||||||
boundaryMargin: EdgeInsets.symmetric(
|
boundaryMargin: EdgeInsets.symmetric(
|
||||||
horizontal: context.screenWidth * 0.3,
|
horizontal: MediaQuery.sizeOf(context).width * 0.3,
|
||||||
vertical: context.screenHeight * 0.3,
|
vertical: MediaQuery.sizeOf(context).height * 0.3,
|
||||||
),
|
),
|
||||||
minScale: 0.5,
|
minScale: 0.5,
|
||||||
maxScale: 3.0,
|
maxScale: 3.0,
|
||||||
@ -430,8 +270,8 @@ class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
|
|||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: _resetSelectionAndZoom,
|
onTap: _resetSelectionAndZoom,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: context.screenWidth * 5,
|
width: MediaQuery.sizeOf(context).width * 5,
|
||||||
height: context.screenHeight * 5,
|
height: MediaQuery.sizeOf(context).height * 5,
|
||||||
child: Stack(children: treeWidgets),
|
child: Stack(children: treeWidgets),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -3,10 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/shared/helpers/space_management_community_dialog_helper.dart';
|
import 'package:syncrow_web/pages/space_management_v2/main_module/shared/helpers/space_management_community_dialog_helper.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/community_structure_header_action_buttons.dart';
|
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/community_structure_header_action_buttons.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/bloc/communities_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/helpers/space_details_dialog_helper.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/helpers/space_details_dialog_helper.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
@ -14,26 +11,6 @@ import 'package:syncrow_web/utils/constants/assets.dart';
|
|||||||
class CommunityStructureHeader extends StatelessWidget {
|
class CommunityStructureHeader extends StatelessWidget {
|
||||||
const CommunityStructureHeader({super.key});
|
const CommunityStructureHeader({super.key});
|
||||||
|
|
||||||
List<SpaceModel> _updateRecursive(
|
|
||||||
List<SpaceModel> spaces,
|
|
||||||
SpaceDetailsModel updatedSpace,
|
|
||||||
) {
|
|
||||||
return spaces.map((space) {
|
|
||||||
if (space.uuid == updatedSpace.uuid) {
|
|
||||||
return space.copyWith(
|
|
||||||
spaceName: updatedSpace.spaceName,
|
|
||||||
icon: updatedSpace.icon,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (space.children.isNotEmpty) {
|
|
||||||
return space.copyWith(
|
|
||||||
children: _updateRecursive(space.children, updatedSpace),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return space;
|
|
||||||
}).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
@ -78,9 +55,8 @@ class CommunityStructureHeader extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Community Structure',
|
'Community Structure',
|
||||||
style: theme.textTheme.headlineLarge?.copyWith(
|
style: theme.textTheme.headlineLarge
|
||||||
color: ColorsManager.blackColor,
|
?.copyWith(color: ColorsManager.blackColor),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
if (selectedCommunity != null)
|
if (selectedCommunity != null)
|
||||||
Row(
|
Row(
|
||||||
@ -91,9 +67,8 @@ class CommunityStructureHeader extends StatelessWidget {
|
|||||||
Flexible(
|
Flexible(
|
||||||
child: SelectableText(
|
child: SelectableText(
|
||||||
selectedCommunity.name,
|
selectedCommunity.name,
|
||||||
style: theme.textTheme.bodyLarge?.copyWith(
|
style: theme.textTheme.bodyLarge
|
||||||
color: ColorsManager.blackColor,
|
?.copyWith(color: ColorsManager.blackColor),
|
||||||
),
|
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -118,24 +93,12 @@ class CommunityStructureHeader extends StatelessWidget {
|
|||||||
CommunityStructureHeaderActionButtons(
|
CommunityStructureHeaderActionButtons(
|
||||||
onDelete: (space) {},
|
onDelete: (space) {},
|
||||||
onDuplicate: (space) {},
|
onDuplicate: (space) {},
|
||||||
onEdit: (space) => SpaceDetailsDialogHelper.showEdit(
|
onEdit: (space) {
|
||||||
|
SpaceDetailsDialogHelper.showEdit(
|
||||||
context,
|
context,
|
||||||
spaceModel: selectedSpace!,
|
spaceModel: selectedSpace!,
|
||||||
communityUuid: selectedCommunity.uuid,
|
|
||||||
onSuccess: (updatedSpaceDetails) {
|
|
||||||
final communitiesBloc = context.read<CommunitiesBloc>();
|
|
||||||
final updatedSpaces = _updateRecursive(
|
|
||||||
selectedCommunity.spaces,
|
|
||||||
updatedSpaceDetails,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
final community = selectedCommunity.copyWith(
|
|
||||||
spaces: updatedSpaces,
|
|
||||||
);
|
|
||||||
|
|
||||||
communitiesBloc.add(CommunitiesUpdateCommunity(community));
|
|
||||||
},
|
},
|
||||||
),
|
|
||||||
selectedSpace: selectedSpace,
|
selectedSpace: selectedSpace,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -2,70 +2,42 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/helpers/space_details_dialog_helper.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/helpers/space_details_dialog_helper.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
class CreateSpaceButton extends StatefulWidget {
|
class CreateSpaceButton extends StatelessWidget {
|
||||||
const CreateSpaceButton({
|
const CreateSpaceButton({super.key});
|
||||||
required this.communityUuid,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
final String communityUuid;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<CreateSpaceButton> createState() => _CreateSpaceButtonState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CreateSpaceButtonState extends State<CreateSpaceButton> {
|
|
||||||
bool _isHovered = false;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Tooltip(
|
return GestureDetector(
|
||||||
margin: const EdgeInsets.symmetric(vertical: 24),
|
onTap: () => SpaceDetailsDialogHelper.showCreate(context),
|
||||||
message: 'Create a new space',
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () => SpaceDetailsDialogHelper.showCreate(
|
|
||||||
context,
|
|
||||||
communityUuid: widget.communityUuid,
|
|
||||||
),
|
|
||||||
child: MouseRegion(
|
|
||||||
onEnter: (_) => setState(() => _isHovered = true),
|
|
||||||
onExit: (_) => setState(() => _isHovered = false),
|
|
||||||
child: AnimatedOpacity(
|
|
||||||
duration: const Duration(milliseconds: 100),
|
|
||||||
opacity: _isHovered ? 1.0 : 0.45,
|
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 150,
|
height: 60,
|
||||||
height: 90,
|
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.grey.withValues(alpha: 0.2),
|
color: Colors.grey.withValues(alpha: 0.5),
|
||||||
spreadRadius: 3,
|
spreadRadius: 5,
|
||||||
blurRadius: 8,
|
blurRadius: 7,
|
||||||
offset: const Offset(0, 4),
|
offset: const Offset(0, 3),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
child: Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: const EdgeInsets.symmetric(vertical: 20),
|
width: 40,
|
||||||
decoration: BoxDecoration(
|
height: 40,
|
||||||
border: Border.all(color: ColorsManager.borderColor, width: 2),
|
decoration: const BoxDecoration(
|
||||||
color: ColorsManager.boxColor,
|
color: ColorsManager.boxColor,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
child: const Center(
|
child: const Icon(
|
||||||
child: Icon(
|
|
||||||
Icons.add,
|
Icons.add,
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ class _SpaceCardWidgetState extends State<SpaceCardWidget> {
|
|||||||
return MouseRegion(
|
return MouseRegion(
|
||||||
onEnter: (_) => setState(() => isHovered = true),
|
onEnter: (_) => setState(() => isHovered = true),
|
||||||
onExit: (_) => setState(() => isHovered = false),
|
onExit: (_) => setState(() => isHovered = false),
|
||||||
|
child: SizedBox(
|
||||||
child: Stack(
|
child: Stack(
|
||||||
clipBehavior: Clip.none,
|
clipBehavior: Clip.none,
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
@ -37,6 +38,7 @@ class _SpaceCardWidgetState extends State<SpaceCardWidget> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ class SpaceCell extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return InkWell(
|
return GestureDetector(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 150,
|
width: 150,
|
||||||
|
@ -13,17 +13,11 @@ class SpaceManagementCommunityStructure extends StatelessWidget {
|
|||||||
final selectionBloc = context.watch<CommunitiesTreeSelectionBloc>().state;
|
final selectionBloc = context.watch<CommunitiesTreeSelectionBloc>().state;
|
||||||
final selectedCommunity = selectionBloc.selectedCommunity;
|
final selectedCommunity = selectionBloc.selectedCommunity;
|
||||||
final selectedSpace = selectionBloc.selectedSpace;
|
final selectedSpace = selectionBloc.selectedSpace;
|
||||||
const spacer = Spacer(flex: 6);
|
const spacer = Spacer(flex: 10);
|
||||||
return Visibility(
|
return Visibility(
|
||||||
visible: selectedCommunity!.spaces.isNotEmpty,
|
visible: selectedCommunity!.spaces.isNotEmpty,
|
||||||
replacement: Row(
|
replacement: const Row(
|
||||||
children: [
|
children: [spacer, Expanded(child: CreateSpaceButton()), spacer],
|
||||||
spacer,
|
|
||||||
Expanded(
|
|
||||||
child: CreateSpaceButton(communityUuid: selectedCommunity.uuid),
|
|
||||||
),
|
|
||||||
spacer
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
@ -46,25 +46,6 @@ class SpaceModel extends Equatable {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
SpaceModel copyWith({
|
|
||||||
String? uuid,
|
|
||||||
DateTime? createdAt,
|
|
||||||
DateTime? updatedAt,
|
|
||||||
String? spaceName,
|
|
||||||
String? icon,
|
|
||||||
List<SpaceModel>? children,
|
|
||||||
}) {
|
|
||||||
return SpaceModel(
|
|
||||||
uuid: uuid ?? this.uuid,
|
|
||||||
createdAt: createdAt ?? this.createdAt,
|
|
||||||
updatedAt: updatedAt ?? this.updatedAt,
|
|
||||||
spaceName: spaceName ?? this.spaceName,
|
|
||||||
icon: icon ?? this.icon,
|
|
||||||
children: children ?? this.children,
|
|
||||||
parent: parent,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [uuid, spaceName, icon, children];
|
List<Object?> get props => [uuid, spaceName, icon, children];
|
||||||
}
|
}
|
||||||
|
@ -1,39 +1,17 @@
|
|||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/bloc/communities_bloc.dart';
|
|
||||||
|
|
||||||
part 'communities_tree_selection_event.dart';
|
part 'communities_tree_selection_event.dart';
|
||||||
part 'communities_tree_selection_state.dart';
|
part 'communities_tree_selection_state.dart';
|
||||||
|
|
||||||
class CommunitiesTreeSelectionBloc
|
class CommunitiesTreeSelectionBloc
|
||||||
extends Bloc<CommunitiesTreeSelectionEvent, CommunitiesTreeSelectionState> {
|
extends Bloc<CommunitiesTreeSelectionEvent, CommunitiesTreeSelectionState> {
|
||||||
CommunitiesTreeSelectionBloc({
|
CommunitiesTreeSelectionBloc() : super(const CommunitiesTreeSelectionState()) {
|
||||||
required CommunitiesBloc communitiesBloc,
|
|
||||||
}) : _communitiesBloc = communitiesBloc,
|
|
||||||
super(const CommunitiesTreeSelectionState()) {
|
|
||||||
on<SelectCommunityEvent>(_onSelectCommunity);
|
on<SelectCommunityEvent>(_onSelectCommunity);
|
||||||
on<SelectSpaceEvent>(_onSelectSpace);
|
on<SelectSpaceEvent>(_onSelectSpace);
|
||||||
on<ClearCommunitiesTreeSelectionEvent>(_onClearSelection);
|
on<ClearCommunitiesTreeSelectionEvent>(_onClearSelection);
|
||||||
on<_CommunitiesStateUpdated>(_onCommunitiesStateUpdated);
|
|
||||||
|
|
||||||
_communitiesSubscription = _communitiesBloc.stream.listen((communitiesState) {
|
|
||||||
if (state.selectedCommunity != null) {
|
|
||||||
add(_CommunitiesStateUpdated(communitiesState));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
final CommunitiesBloc _communitiesBloc;
|
|
||||||
late final StreamSubscription<CommunitiesState> _communitiesSubscription;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> close() {
|
|
||||||
_communitiesSubscription.cancel();
|
|
||||||
return super.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onSelectCommunity(
|
void _onSelectCommunity(
|
||||||
@ -66,59 +44,4 @@ class CommunitiesTreeSelectionBloc
|
|||||||
) {
|
) {
|
||||||
emit(const CommunitiesTreeSelectionState());
|
emit(const CommunitiesTreeSelectionState());
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onCommunitiesStateUpdated(
|
|
||||||
_CommunitiesStateUpdated event,
|
|
||||||
Emitter<CommunitiesTreeSelectionState> emit,
|
|
||||||
) {
|
|
||||||
if (state.selectedCommunity == null) return;
|
|
||||||
|
|
||||||
final communities = event.communitiesState.communities;
|
|
||||||
try {
|
|
||||||
final updatedCommunity = communities.firstWhere(
|
|
||||||
(c) => c.uuid == state.selectedCommunity!.uuid,
|
|
||||||
);
|
|
||||||
|
|
||||||
var updatedSelectedSpace = state.selectedSpace;
|
|
||||||
if (state.selectedSpace != null) {
|
|
||||||
updatedSelectedSpace = _findSpaceInCommunity(
|
|
||||||
updatedCommunity,
|
|
||||||
state.selectedSpace!.uuid,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
emit(
|
|
||||||
state.copyWith(
|
|
||||||
selectedCommunity: updatedCommunity,
|
|
||||||
selectedSpace: updatedSelectedSpace,
|
|
||||||
clearSelectedSpace: updatedSelectedSpace == null,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} catch (_) {
|
|
||||||
add(const ClearCommunitiesTreeSelectionEvent());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SpaceModel? _findSpaceInCommunity(CommunityModel community, String spaceUuid) {
|
|
||||||
try {
|
|
||||||
return _findSpaceRecursive(community.spaces, spaceUuid);
|
|
||||||
} catch (_) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SpaceModel _findSpaceRecursive(List<SpaceModel> spaces, String spaceUuid) {
|
|
||||||
for (final space in spaces) {
|
|
||||||
if (space.uuid == spaceUuid) {
|
|
||||||
return space;
|
|
||||||
}
|
|
||||||
if (space.children.isNotEmpty) {
|
|
||||||
try {
|
|
||||||
return _findSpaceRecursive(space.children, spaceUuid);
|
|
||||||
} catch (_) {
|
|
||||||
// not found in this branch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw Exception('Space not found');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -29,12 +29,3 @@ final class ClearCommunitiesTreeSelectionEvent
|
|||||||
extends CommunitiesTreeSelectionEvent {
|
extends CommunitiesTreeSelectionEvent {
|
||||||
const ClearCommunitiesTreeSelectionEvent();
|
const ClearCommunitiesTreeSelectionEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
final class _CommunitiesStateUpdated extends CommunitiesTreeSelectionEvent {
|
|
||||||
const _CommunitiesStateUpdated(this.communitiesState);
|
|
||||||
|
|
||||||
final CommunitiesState communitiesState;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [communitiesState];
|
|
||||||
}
|
|
||||||
|
@ -12,14 +12,18 @@ final class CommunitiesTreeSelectionState extends Equatable {
|
|||||||
CommunitiesTreeSelectionState copyWith({
|
CommunitiesTreeSelectionState copyWith({
|
||||||
CommunityModel? selectedCommunity,
|
CommunityModel? selectedCommunity,
|
||||||
SpaceModel? selectedSpace,
|
SpaceModel? selectedSpace,
|
||||||
bool clearSelectedSpace = false,
|
List<CommunityModel>? expandedCommunities,
|
||||||
|
List<SpaceModel>? expandedSpaces,
|
||||||
}) {
|
}) {
|
||||||
return CommunitiesTreeSelectionState(
|
return CommunitiesTreeSelectionState(
|
||||||
selectedCommunity: selectedCommunity ?? this.selectedCommunity,
|
selectedCommunity: selectedCommunity ?? this.selectedCommunity,
|
||||||
selectedSpace: clearSelectedSpace ? null : selectedSpace ?? this.selectedSpace,
|
selectedSpace: selectedSpace ?? this.selectedSpace,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [selectedCommunity, selectedSpace];
|
List<Object?> get props => [
|
||||||
|
selectedCommunity,
|
||||||
|
selectedSpace,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -13,14 +13,14 @@ class CommunitiesTreeFailureWidget extends StatelessWidget {
|
|||||||
return Expanded(
|
return Expanded(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
spacing: 16,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
SelectableText(
|
Text(
|
||||||
errorMessage ?? 'Something went wrong',
|
errorMessage ?? 'Something went wrong',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
FilledButton(
|
const SizedBox(height: 16),
|
||||||
|
ElevatedButton(
|
||||||
onPressed: () => context.read<CommunitiesBloc>().add(
|
onPressed: () => context.read<CommunitiesBloc>().add(
|
||||||
LoadCommunities(
|
LoadCommunities(
|
||||||
LoadCommunitiesParam(
|
LoadCommunitiesParam(
|
||||||
|
@ -40,6 +40,16 @@ class SpaceDetailsModel extends Equatable {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'uuid': uuid,
|
||||||
|
'spaceName': spaceName,
|
||||||
|
'icon': icon,
|
||||||
|
'productAllocations': productAllocations.map((e) => e.toJson()).toList(),
|
||||||
|
'subspaces': subspaces.map((e) => e.toJson()).toList(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
SpaceDetailsModel copyWith({
|
SpaceDetailsModel copyWith({
|
||||||
String? uuid,
|
String? uuid,
|
||||||
String? spaceName,
|
String? spaceName,
|
||||||
@ -79,6 +89,14 @@ class ProductAllocation extends Equatable {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'uuid': uuid,
|
||||||
|
'product': product.toJson(),
|
||||||
|
'tag': tag.toJson(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
ProductAllocation copyWith({
|
ProductAllocation copyWith({
|
||||||
String? uuid,
|
String? uuid,
|
||||||
Product? product,
|
Product? product,
|
||||||
@ -116,6 +134,14 @@ class Subspace extends Equatable {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'uuid': uuid,
|
||||||
|
'name': name,
|
||||||
|
'productAllocations': productAllocations.map((e) => e.toJson()).toList(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Subspace copyWith({
|
Subspace copyWith({
|
||||||
String? uuid,
|
String? uuid,
|
||||||
String? name,
|
String? name,
|
||||||
|
@ -2,37 +2,23 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/data/services/remote_space_details_service.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/data/services/remote_space_details_service.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/bloc/space_details_bloc.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/bloc/space_details_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_details_dialog.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_details_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/update_space/data/services/remote_update_space_service.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/update_space/domain/params/update_space_param.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/update_space/presentation/bloc/update_space_bloc.dart';
|
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
|
|
||||||
abstract final class SpaceDetailsDialogHelper {
|
abstract final class SpaceDetailsDialogHelper {
|
||||||
static void showCreate(
|
static void showCreate(BuildContext context) {
|
||||||
BuildContext context, {
|
|
||||||
required String communityUuid,
|
|
||||||
}) {
|
|
||||||
showDialog<void>(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => MultiBlocProvider(
|
builder: (_) => BlocProvider(
|
||||||
providers: [
|
|
||||||
BlocProvider(
|
|
||||||
create: (context) => SpaceDetailsBloc(
|
create: (context) => SpaceDetailsBloc(
|
||||||
RemoteSpaceDetailsService(httpService: HTTPService()),
|
RemoteSpaceDetailsService(httpService: HTTPService()),
|
||||||
),
|
),
|
||||||
),
|
child: SpaceDetailsDialog(
|
||||||
],
|
|
||||||
child: Builder(
|
|
||||||
builder: (context) => SpaceDetailsDialog(
|
|
||||||
context: context,
|
context: context,
|
||||||
title: const SelectableText('Create Space'),
|
title: const SelectableText('Create Space'),
|
||||||
spaceModel: SpaceModel.empty(),
|
spaceModel: SpaceModel.empty(),
|
||||||
onSave: (space) {},
|
onSave: (space) {},
|
||||||
communityUuid: communityUuid,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -41,98 +27,20 @@ abstract final class SpaceDetailsDialogHelper {
|
|||||||
static void showEdit(
|
static void showEdit(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
required SpaceModel spaceModel,
|
required SpaceModel spaceModel,
|
||||||
required String communityUuid,
|
|
||||||
required void Function(SpaceDetailsModel updatedSpaceDetails)? onSuccess,
|
|
||||||
}) {
|
}) {
|
||||||
showDialog<void>(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => MultiBlocProvider(
|
builder: (_) => BlocProvider(
|
||||||
providers: [
|
|
||||||
BlocProvider(
|
|
||||||
create: (context) => SpaceDetailsBloc(
|
create: (context) => SpaceDetailsBloc(
|
||||||
RemoteSpaceDetailsService(httpService: HTTPService()),
|
RemoteSpaceDetailsService(httpService: HTTPService()),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
BlocProvider(
|
|
||||||
create: (context) => UpdateSpaceBloc(
|
|
||||||
RemoteUpdateSpaceService(HTTPService()),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
child: Builder(
|
|
||||||
builder: (context) => BlocListener<UpdateSpaceBloc, UpdateSpaceState>(
|
|
||||||
listener: (context, state) => _updateListener(
|
|
||||||
context,
|
|
||||||
state,
|
|
||||||
onSuccess,
|
|
||||||
),
|
|
||||||
child: SpaceDetailsDialog(
|
child: SpaceDetailsDialog(
|
||||||
context: context,
|
context: context,
|
||||||
title: const SelectableText('Edit Space'),
|
title: const SelectableText('Edit Space'),
|
||||||
spaceModel: spaceModel,
|
spaceModel: spaceModel,
|
||||||
onSave: (space) => context.read<UpdateSpaceBloc>().add(
|
onSave: (space) {},
|
||||||
UpdateSpace(
|
|
||||||
UpdateSpaceParam(
|
|
||||||
communityUuid: communityUuid,
|
|
||||||
space: space,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
communityUuid: communityUuid,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _updateListener(
|
|
||||||
BuildContext context,
|
|
||||||
UpdateSpaceState state,
|
|
||||||
void Function(SpaceDetailsModel updatedSpaceDetails)? onSuccess,
|
|
||||||
) {
|
|
||||||
return switch (state) {
|
|
||||||
UpdateSpaceInitial() => null,
|
|
||||||
UpdateSpaceLoading() => _onLoading(context),
|
|
||||||
UpdateSpaceSuccess(:final space) =>
|
|
||||||
_onUpdateSuccess(context, space, onSuccess),
|
|
||||||
UpdateSpaceFailure(:final errorMessage) => _onError(context, errorMessage),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _onUpdateSuccess(
|
|
||||||
BuildContext context,
|
|
||||||
SpaceDetailsModel space,
|
|
||||||
void Function(SpaceDetailsModel updatedSpaceDetails)? onSuccess,
|
|
||||||
) {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
onSuccess?.call(space);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _onLoading(BuildContext context) {
|
|
||||||
showDialog<void>(
|
|
||||||
context: context,
|
|
||||||
barrierDismissible: false,
|
|
||||||
builder: (_) => const Center(child: CircularProgressIndicator()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _onError(BuildContext context, String errorMessage) {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
showDialog<void>(
|
|
||||||
context: context,
|
|
||||||
barrierDismissible: false,
|
|
||||||
builder: (_) => AlertDialog(
|
|
||||||
title: const Text('Error'),
|
|
||||||
content: Text(errorMessage),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: Navigator.of(context).pop,
|
|
||||||
child: const Text('OK'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/params/load_space_details_param.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/params/load_space_details_param.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/bloc/space_details_bloc.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/bloc/space_details_bloc.dart';
|
||||||
@ -14,7 +15,6 @@ class SpaceDetailsDialog extends StatefulWidget {
|
|||||||
required this.spaceModel,
|
required this.spaceModel,
|
||||||
required this.onSave,
|
required this.onSave,
|
||||||
required this.context,
|
required this.context,
|
||||||
required this.communityUuid,
|
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -22,7 +22,6 @@ class SpaceDetailsDialog extends StatefulWidget {
|
|||||||
final SpaceModel spaceModel;
|
final SpaceModel spaceModel;
|
||||||
final void Function(SpaceDetailsModel space) onSave;
|
final void Function(SpaceDetailsModel space) onSave;
|
||||||
final BuildContext context;
|
final BuildContext context;
|
||||||
final String communityUuid;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<SpaceDetailsDialog> createState() => _SpaceDetailsDialogState();
|
State<SpaceDetailsDialog> createState() => _SpaceDetailsDialogState();
|
||||||
@ -36,7 +35,11 @@ class _SpaceDetailsDialogState extends State<SpaceDetailsDialog> {
|
|||||||
if (!isCreateMode) {
|
if (!isCreateMode) {
|
||||||
final param = LoadSpaceDetailsParam(
|
final param = LoadSpaceDetailsParam(
|
||||||
spaceUuid: widget.spaceModel.uuid,
|
spaceUuid: widget.spaceModel.uuid,
|
||||||
communityUuid: widget.communityUuid,
|
communityUuid: widget.context
|
||||||
|
.read<CommunitiesTreeSelectionBloc>()
|
||||||
|
.state
|
||||||
|
.selectedCommunity!
|
||||||
|
.uuid,
|
||||||
);
|
);
|
||||||
widget.context.read<SpaceDetailsBloc>().add(LoadSpaceDetails(param));
|
widget.context.read<SpaceDetailsBloc>().add(LoadSpaceDetails(param));
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ class _SpaceSubSpacesDialogState extends State<SpaceSubSpacesDialog> {
|
|||||||
..._subspaces,
|
..._subspaces,
|
||||||
Subspace(
|
Subspace(
|
||||||
name: name,
|
name: name,
|
||||||
uuid: '${const Uuid().v4()}-NewTag',
|
uuid: const Uuid().v4(),
|
||||||
productAllocations: const [],
|
productAllocations: const [],
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
@ -3,19 +3,41 @@ import 'package:equatable/equatable.dart';
|
|||||||
class Tag extends Equatable {
|
class Tag extends Equatable {
|
||||||
final String uuid;
|
final String uuid;
|
||||||
final String name;
|
final String name;
|
||||||
|
final String createdAt;
|
||||||
|
final String updatedAt;
|
||||||
|
|
||||||
const Tag({
|
const Tag({
|
||||||
required this.uuid,
|
required this.uuid,
|
||||||
required this.name,
|
required this.name,
|
||||||
|
required this.createdAt,
|
||||||
|
required this.updatedAt,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
factory Tag.empty() => const Tag(
|
||||||
|
uuid: '',
|
||||||
|
name: '',
|
||||||
|
createdAt: '',
|
||||||
|
updatedAt: '',
|
||||||
|
);
|
||||||
|
|
||||||
factory Tag.fromJson(Map<String, dynamic> json) {
|
factory Tag.fromJson(Map<String, dynamic> json) {
|
||||||
return Tag(
|
return Tag(
|
||||||
uuid: json['uuid'] as String,
|
uuid: json['uuid'] as String,
|
||||||
name: json['name'] as String,
|
name: json['name'] as String,
|
||||||
|
createdAt: json['createdAt'] as String,
|
||||||
|
updatedAt: json['updatedAt'] as String,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
Map<String, dynamic> toJson() {
|
||||||
List<Object?> get props => [uuid, name];
|
return {
|
||||||
|
'uuid': uuid,
|
||||||
|
'name': name,
|
||||||
|
'createdAt': createdAt,
|
||||||
|
'updatedAt': updatedAt,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [uuid, name, createdAt, updatedAt];
|
||||||
}
|
}
|
||||||
|
@ -214,12 +214,9 @@ class _AssignTagsDialogState extends State<AssignTagsDialog> {
|
|||||||
for (final product in newProducts) {
|
for (final product in newProducts) {
|
||||||
_space.productAllocations.add(
|
_space.productAllocations.add(
|
||||||
ProductAllocation(
|
ProductAllocation(
|
||||||
uuid: '${const Uuid().v4()}-NewProductUuid',
|
uuid: const Uuid().v4(),
|
||||||
product: product,
|
product: product,
|
||||||
tag: Tag(
|
tag: Tag.empty(),
|
||||||
uuid: '${const Uuid().v4()}-NewTag',
|
|
||||||
name: '',
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:syncrow_web/pages/space_management_v2/modules/tags/domain/models/tag.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/tags/domain/models/tag.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
|
||||||
|
|
||||||
class ProductTagField extends StatefulWidget {
|
class ProductTagField extends StatefulWidget {
|
||||||
final List<Tag> items;
|
final List<Tag> items;
|
||||||
@ -54,8 +53,13 @@ class _ProductTagFieldState extends State<ProductTagField> {
|
|||||||
void _submit(String value) {
|
void _submit(String value) {
|
||||||
final lowerCaseValue = value.toLowerCase();
|
final lowerCaseValue = value.toLowerCase();
|
||||||
final selectedTag = widget.items.firstWhere(
|
final selectedTag = widget.items.firstWhere(
|
||||||
(e) => e.name.toLowerCase() == lowerCaseValue,
|
(tag) => tag.name.toLowerCase() == lowerCaseValue,
|
||||||
orElse: () => Tag(uuid: '${const Uuid().v4()}-NewTag', name: value),
|
orElse: () => Tag(
|
||||||
|
name: value,
|
||||||
|
uuid: '',
|
||||||
|
createdAt: '',
|
||||||
|
updatedAt: '',
|
||||||
|
),
|
||||||
);
|
);
|
||||||
widget.onSelected(selectedTag);
|
widget.onSelected(selectedTag);
|
||||||
_closeDropdown();
|
_closeDropdown();
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/update_space/domain/params/update_space_param.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/update_space/domain/services/update_space_service.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/update_space/domain/services/update_space_service.dart';
|
||||||
import 'package:syncrow_web/services/api/api_exception.dart';
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
@ -14,23 +12,17 @@ class RemoteUpdateSpaceService implements UpdateSpaceService {
|
|||||||
static const _defaultErrorMessage = 'Failed to update space';
|
static const _defaultErrorMessage = 'Failed to update space';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<SpaceDetailsModel> updateSpace(UpdateSpaceParam param) async {
|
Future<SpaceDetailsModel> updateSpace(SpaceDetailsModel space) async {
|
||||||
try {
|
try {
|
||||||
final path = await _makeUrl(param);
|
final response = await _httpService.put(
|
||||||
await _httpService.put(
|
path: 'endpoint',
|
||||||
path: path,
|
body: space.toJson(),
|
||||||
body: param.toJson(),
|
expectedResponseModel: (data) => SpaceDetailsModel.fromJson(
|
||||||
expectedResponseModel: (data) {
|
data as Map<String, dynamic>,
|
||||||
final response = data as Map<String, dynamic>;
|
),
|
||||||
final isSuccess = response['success'] as bool;
|
|
||||||
if (!isSuccess) {
|
|
||||||
throw APIException(response['error'] as String);
|
|
||||||
}
|
|
||||||
return isSuccess;
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return param.space;
|
return response;
|
||||||
} on DioException catch (e) {
|
} on DioException catch (e) {
|
||||||
final message = e.response?.data as Map<String, dynamic>?;
|
final message = e.response?.data as Map<String, dynamic>?;
|
||||||
final error = message?['error'] as Map<String, dynamic>?;
|
final error = message?['error'] as Map<String, dynamic>?;
|
||||||
@ -45,23 +37,4 @@ class RemoteUpdateSpaceService implements UpdateSpaceService {
|
|||||||
throw APIException(formattedErrorMessage);
|
throw APIException(formattedErrorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> _makeUrl(UpdateSpaceParam param) async {
|
|
||||||
final projectUuid = await ProjectManager.getProjectUUID();
|
|
||||||
if (projectUuid == null || projectUuid.isEmpty) {
|
|
||||||
throw APIException('Project UUID is not set');
|
|
||||||
}
|
|
||||||
|
|
||||||
final spaceUuid = param.space.uuid;
|
|
||||||
if (spaceUuid.isEmpty) {
|
|
||||||
throw APIException('Space UUID is not set');
|
|
||||||
}
|
|
||||||
|
|
||||||
final communityUuid = param.communityUuid;
|
|
||||||
if (communityUuid.isEmpty) {
|
|
||||||
throw APIException('Community UUID is not set');
|
|
||||||
}
|
|
||||||
|
|
||||||
return '/projects/$projectUuid/communities/$communityUuid/spaces/$spaceUuid';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
|
||||||
|
|
||||||
class UpdateSpaceParam {
|
|
||||||
UpdateSpaceParam({
|
|
||||||
required this.space,
|
|
||||||
required this.communityUuid,
|
|
||||||
});
|
|
||||||
|
|
||||||
final SpaceDetailsModel space;
|
|
||||||
final String communityUuid;
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
return {
|
|
||||||
'spaceName': space.spaceName,
|
|
||||||
'icon': space.icon,
|
|
||||||
'subspaces': space.subspaces.map((e) => e._toJson()).toList(),
|
|
||||||
'productAllocations':
|
|
||||||
space.productAllocations.map((e) => e._toJson()).toList(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension _ProductAllocationToJson on ProductAllocation {
|
|
||||||
Map<String, dynamic> _toJson() {
|
|
||||||
final isNewTag = tag.uuid.isEmpty;
|
|
||||||
return <String, dynamic>{
|
|
||||||
if (isNewTag) 'tagName': tag.name else 'tagUuid': tag.uuid,
|
|
||||||
'productUuid': product.uuid,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension _SubspaceToJson on Subspace {
|
|
||||||
Map<String, dynamic> _toJson() {
|
|
||||||
final isNewSubspace = uuid.endsWith('-NewTag');
|
|
||||||
return <String, dynamic>{
|
|
||||||
if (!isNewSubspace) 'uuid': uuid,
|
|
||||||
'subspaceName': name,
|
|
||||||
'productAllocations': productAllocations.map((e) => e._toJson()).toList(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,5 @@
|
|||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/update_space/domain/params/update_space_param.dart';
|
|
||||||
|
|
||||||
abstract interface class UpdateSpaceService {
|
abstract class UpdateSpaceService {
|
||||||
Future<SpaceDetailsModel> updateSpace(UpdateSpaceParam param);
|
Future<SpaceDetailsModel> updateSpace(SpaceDetailsModel space);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/update_space/domain/params/update_space_param.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/update_space/domain/services/update_space_service.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/update_space/domain/services/update_space_service.dart';
|
||||||
import 'package:syncrow_web/services/api/api_exception.dart';
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
|
|
||||||
@ -21,7 +20,7 @@ class UpdateSpaceBloc extends Bloc<UpdateSpaceEvent, UpdateSpaceState> {
|
|||||||
) async {
|
) async {
|
||||||
emit(UpdateSpaceLoading());
|
emit(UpdateSpaceLoading());
|
||||||
try {
|
try {
|
||||||
final updatedSpace = await _updateSpaceService.updateSpace(event.param);
|
final updatedSpace = await _updateSpaceService.updateSpace(event.space);
|
||||||
emit(UpdateSpaceSuccess(updatedSpace));
|
emit(UpdateSpaceSuccess(updatedSpace));
|
||||||
} on APIException catch (e) {
|
} on APIException catch (e) {
|
||||||
emit(UpdateSpaceFailure(e.message));
|
emit(UpdateSpaceFailure(e.message));
|
||||||
|
@ -8,10 +8,10 @@ sealed class UpdateSpaceEvent extends Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class UpdateSpace extends UpdateSpaceEvent {
|
final class UpdateSpace extends UpdateSpaceEvent {
|
||||||
const UpdateSpace(this.param);
|
const UpdateSpace(this.space);
|
||||||
|
|
||||||
final UpdateSpaceParam param;
|
final SpaceDetailsModel space;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [param];
|
List<Object> get props => [space];
|
||||||
}
|
}
|
||||||
|
@ -21,10 +21,10 @@ final class UpdateSpaceSuccess extends UpdateSpaceState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class UpdateSpaceFailure extends UpdateSpaceState {
|
final class UpdateSpaceFailure extends UpdateSpaceState {
|
||||||
final String errorMessage;
|
final String message;
|
||||||
|
|
||||||
const UpdateSpaceFailure(this.errorMessage);
|
const UpdateSpaceFailure(this.message);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [errorMessage];
|
List<Object> get props => [message];
|
||||||
}
|
}
|
||||||
|
@ -34,8 +34,9 @@ class UserPermissionApi {
|
|||||||
path: ApiEndpoints.roleTypes,
|
path: ApiEndpoints.roleTypes,
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
final List<RoleTypeModel> fetchedRoles =
|
final List<RoleTypeModel> fetchedRoles = (json['data'] as List)
|
||||||
(json['data'] as List).map((item) => RoleTypeModel.fromJson(item)).toList();
|
.map((item) => RoleTypeModel.fromJson(item))
|
||||||
|
.toList();
|
||||||
return fetchedRoles;
|
return fetchedRoles;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -47,7 +48,9 @@ class UserPermissionApi {
|
|||||||
path: ApiEndpoints.permission.replaceAll("roleUuid", roleUuid),
|
path: ApiEndpoints.permission.replaceAll("roleUuid", roleUuid),
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
return (json as List).map((data) => PermissionOption.fromJson(data)).toList();
|
return (json as List)
|
||||||
|
.map((data) => PermissionOption.fromJson(data))
|
||||||
|
.toList();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response ?? [];
|
return response ?? [];
|
||||||
@ -57,7 +60,7 @@ class UserPermissionApi {
|
|||||||
String? firstName,
|
String? firstName,
|
||||||
String? lastName,
|
String? lastName,
|
||||||
String? email,
|
String? email,
|
||||||
String? jobTitle,
|
String? companyName,
|
||||||
String? phoneNumber,
|
String? phoneNumber,
|
||||||
String? roleUuid,
|
String? roleUuid,
|
||||||
List<String>? spaceUuids,
|
List<String>? spaceUuids,
|
||||||
@ -68,7 +71,7 @@ class UserPermissionApi {
|
|||||||
"firstName": firstName,
|
"firstName": firstName,
|
||||||
"lastName": lastName,
|
"lastName": lastName,
|
||||||
"email": email,
|
"email": email,
|
||||||
"jobTitle": jobTitle != '' ? jobTitle : null,
|
"companyName": companyName != '' ? companyName : null,
|
||||||
"phoneNumber": phoneNumber != '' ? phoneNumber : null,
|
"phoneNumber": phoneNumber != '' ? phoneNumber : null,
|
||||||
"roleUuid": roleUuid,
|
"roleUuid": roleUuid,
|
||||||
"projectUuid": projectUuid,
|
"projectUuid": projectUuid,
|
||||||
@ -140,7 +143,7 @@ class UserPermissionApi {
|
|||||||
String? firstName,
|
String? firstName,
|
||||||
String? userId,
|
String? userId,
|
||||||
String? lastName,
|
String? lastName,
|
||||||
String? jobTitle,
|
String? companyName,
|
||||||
String? phoneNumber,
|
String? phoneNumber,
|
||||||
String? roleUuid,
|
String? roleUuid,
|
||||||
List<String>? spaceUuids,
|
List<String>? spaceUuids,
|
||||||
@ -150,8 +153,8 @@ class UserPermissionApi {
|
|||||||
final body = <String, dynamic>{
|
final body = <String, dynamic>{
|
||||||
"firstName": firstName,
|
"firstName": firstName,
|
||||||
"lastName": lastName,
|
"lastName": lastName,
|
||||||
"jobTitle": jobTitle != '' ? jobTitle : " ",
|
"companyName": companyName != '' ? companyName : ' ',
|
||||||
"phoneNumber": phoneNumber != '' ? phoneNumber : " ",
|
"phoneNumber": phoneNumber != '' ? phoneNumber : ' ',
|
||||||
"roleUuid": roleUuid,
|
"roleUuid": roleUuid,
|
||||||
"projectUuid": projectUuid,
|
"projectUuid": projectUuid,
|
||||||
"spaceUuids": spaceUuids,
|
"spaceUuids": spaceUuids,
|
||||||
@ -190,12 +193,17 @@ class UserPermissionApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> changeUserStatusById(userUuid, status, String projectUuid) async {
|
Future<bool> changeUserStatusById(
|
||||||
|
userUuid, status, String projectUuid) async {
|
||||||
try {
|
try {
|
||||||
Map<String, dynamic> bodya = {"disable": status, "projectUuid": projectUuid};
|
Map<String, dynamic> bodya = {
|
||||||
|
"disable": status,
|
||||||
|
"projectUuid": projectUuid
|
||||||
|
};
|
||||||
|
|
||||||
final response = await _httpService.put(
|
final response = await _httpService.put(
|
||||||
path: ApiEndpoints.changeUserStatus.replaceAll("{invitedUserUuid}", userUuid),
|
path: ApiEndpoints.changeUserStatus
|
||||||
|
.replaceAll("{invitedUserUuid}", userUuid),
|
||||||
body: bodya,
|
body: bodya,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
return json['success'];
|
return json['success'];
|
||||||
|
Reference in New Issue
Block a user