diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart new file mode 100644 index 0000000..0b9ceb3 --- /dev/null +++ b/lib/api/api_client.dart @@ -0,0 +1,28 @@ +import 'package:http/http.dart' as http; +import 'package:shared_preferences/shared_preferences.dart'; + +class ApiClient { + static final ApiClient instance = ApiClient('http://10.0.2.2:5032/api'); + final String _baseUrl; + + ApiClient(this._baseUrl); + + Future get(String endpoint) async { + final prefs = await SharedPreferences.getInstance(); + final token = prefs.getString('auth_token'); + + if (token == null) { + throw Exception('No token found. User might not be logged in.'); + } + + final url = '$_baseUrl/$endpoint'; + print("Url received: $url"); + final headers = { + 'Authorization': 'Bearer $token', + 'Content-Type': 'application/json', + }; + + return await http.get(Uri.parse(url), headers: headers); + } +} + diff --git a/lib/api/api_service.dart b/lib/api/api_service.dart new file mode 100644 index 0000000..bb6ef0d --- /dev/null +++ b/lib/api/api_service.dart @@ -0,0 +1,22 @@ +import 'dart:convert'; +import 'package:maxdash/api/api_client.dart'; + +class ApiService { + final ApiClient _apiClient = ApiClient.instance; + + Future getProjectSummaries() async { + try { + final response = await _apiClient.get('project/list'); + + if (response.statusCode == 200) { + // print('Response body: ${response.body}'); // Parsed JSON + return jsonDecode(response.body); + + } else { + throw Exception('Failed to load project summaries: ${response.statusCode}'); + } + } catch (e) { + throw Exception('Error in getProjectSummaries: $e'); + } + } +} diff --git a/lib/controller/dashboard/project_controller.dart b/lib/controller/dashboard/project_controller.dart index 5ca8433..b4ea219 100644 --- a/lib/controller/dashboard/project_controller.dart +++ b/lib/controller/dashboard/project_controller.dart @@ -2,12 +2,15 @@ import 'package:maxdash/controller/my_controller.dart'; import 'package:maxdash/model/chart_model.dart'; import 'package:maxdash/model/project_summary_model.dart'; import 'package:maxdash/model/task_list_model.dart'; +import 'package:maxdash/model/ProjectSummaryApiModel.dart'; +import 'package:maxdash/api/api_service.dart'; import 'package:syncfusion_flutter_charts/charts.dart'; class ProjectController extends MyController { TooltipBehavior? tooltipBehavior; List task = []; - List projectSummary = []; + List projectSummary = []; // Dummy data (local) + List projectSummaryApiList = []; // API data List? chartData; @override @@ -20,6 +23,11 @@ class ProjectController extends MyController { projectSummary = value.sublist(0, 5); update(); }); + + // Fetch project summary from API + fetchProjectSummariesFromApi(); + + // Dummy chart data chartData = [ ChartSampleData(x: 'Jan', y: 10, secondSeriesYValue: 8, thirdSeriesYValue: 12), ChartSampleData(x: 'Feb', y: 5, secondSeriesYValue: 6, thirdSeriesYValue: 7), @@ -43,4 +51,19 @@ class ProjectController extends MyController { task.isSelectTask = !task.isSelectTask; update(); } + + Future fetchProjectSummariesFromApi() async { + try { + final response = await ApiService().getProjectSummaries(); + + if (response != null && response is List) { + projectSummaryApiList = response + .map((json) => ProjectSummaryApiModel.fromJson(json)) + .toList(); + update(); + } + } catch (e) { + print('Error loading API project summaries: $e'); + } + } } diff --git a/lib/model/ProjectSummaryApiModel.dart b/lib/model/ProjectSummaryApiModel.dart new file mode 100644 index 0000000..020095e --- /dev/null +++ b/lib/model/ProjectSummaryApiModel.dart @@ -0,0 +1,31 @@ +class ProjectSummaryApiModel { + final int id; + final String name; + final String projectAddress; + final String contactPerson; + final DateTime startDate; + final DateTime endDate; + final int projectStatusId; + + ProjectSummaryApiModel({ + required this.id, + required this.name, + required this.projectAddress, + required this.contactPerson, + required this.startDate, + required this.endDate, + required this.projectStatusId, + }); + + factory ProjectSummaryApiModel.fromJson(Map json) { + return ProjectSummaryApiModel( + id: json['id'], + name: json['name'], + projectAddress: json['projectAddress'], + contactPerson: json['contactPerson'], + startDate: DateTime.parse(json['startDate']), + endDate: DateTime.parse(json['endDate']), + projectStatusId: json['projectStatusId'], + ); + } +} diff --git a/lib/view/dashboard/project_screen.dart b/lib/view/dashboard/project_screen.dart index f16e7bb..17f6960 100644 --- a/lib/view/dashboard/project_screen.dart +++ b/lib/view/dashboard/project_screen.dart @@ -370,66 +370,55 @@ class _ProjectScreenState extends State with UIMixin { } Widget projectSummary() { - return MyCard.bordered( - borderRadiusAll: 4, + return MyCard.bordered( + borderRadiusAll: 4, border: Border.all(color: Colors.grey.withValues(alpha:.2)), - shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom), - paddingAll: 24, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ + shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom), + paddingAll: 24, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ MyText.bodyMedium("Project Summary", fontWeight: 600), - MySpacing.height(24), - SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: DataTable( - sortAscending: true, - columnSpacing: 84, - onSelectAll: (_) => {}, - headingRowColor: WidgetStatePropertyAll(contentTheme.primary.withAlpha(40)), - dataRowMaxHeight: 60, - showBottomBorder: true, - clipBehavior: Clip.antiAliasWithSaveLayer, - border: TableBorder.all(borderRadius: BorderRadius.circular(4), style: BorderStyle.solid, width: .4, color: Colors.grey), - columns: [ - DataColumn(label: MyText.labelLarge('S.No', color: contentTheme.primary)), - DataColumn(label: MyText.labelLarge('Title', color: contentTheme.primary)), - DataColumn(label: MyText.labelLarge('Assign to', color: contentTheme.primary)), - DataColumn(label: MyText.labelLarge('Due Date', color: contentTheme.primary)), - DataColumn(label: MyText.labelLarge('Priority', color: contentTheme.primary)), - DataColumn(label: MyText.labelLarge('Status', color: contentTheme.primary)), - DataColumn(label: MyText.labelLarge('Action', color: contentTheme.primary)), - ], - rows: controller.projectSummary - .mapIndexed((index, data) => DataRow(cells: [ - DataCell(MyText.bodyMedium("#${data.id}", fontWeight: 600)), - DataCell(MyText.bodyMedium(data.title, fontWeight: 600)), - DataCell(MyText.bodyMedium(data.assignTo, fontWeight: 600)), - DataCell(MyText.bodyMedium(Utils.getDateStringFromDateTime(data.date), fontWeight: 600)), - DataCell(MyText.bodyMedium(data.priority, fontWeight: 600)), - DataCell(MyText.bodyMedium(data.status, fontWeight: 600)), - DataCell(Row( - children: [ - MyContainer( - onTap: () {}, - color: contentTheme.primary, - paddingAll: 8, - child: Icon(LucideIcons.download, size: 16, color: contentTheme.onPrimary), - ), - MySpacing.width(12), - MyContainer( - onTap: () {}, - color: contentTheme.secondary, - paddingAll: 8, - child: Icon(LucideIcons.pencil, size: 16, color: contentTheme.onPrimary), - ), - ], - )) - ])) + MySpacing.height(24), + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: DataTable( + sortAscending: true, + columnSpacing: 84, + onSelectAll: (_) => {}, + headingRowColor: WidgetStatePropertyAll(contentTheme.primary.withAlpha(40)), + dataRowMaxHeight: 60, + showBottomBorder: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + border: TableBorder.all( + borderRadius: BorderRadius.circular(4), + style: BorderStyle.solid, + width: .4, + color: Colors.grey, + ), + columns: [ + DataColumn(label: MyText.labelLarge('S.No', color: contentTheme.primary)), + DataColumn(label: MyText.labelLarge('Name', color: contentTheme.primary)), + DataColumn(label: MyText.labelLarge('Address', color: contentTheme.primary)), + DataColumn(label: MyText.labelLarge('Contact Person', color: contentTheme.primary)), + DataColumn(label: MyText.labelLarge('Start Date', color: contentTheme.primary)), + DataColumn(label: MyText.labelLarge('End Date', color: contentTheme.primary)), + DataColumn(label: MyText.labelLarge('Status ID', color: contentTheme.primary)), + ], + rows: controller.projectSummaryApiList + .mapIndexed((index, data) => DataRow(cells: [ + DataCell(MyText.bodyMedium("#${index + 1}", fontWeight: 600)), + DataCell(MyText.bodyMedium(data.name, fontWeight: 600)), + DataCell(MyText.bodyMedium(data.projectAddress, fontWeight: 600)), + DataCell(MyText.bodyMedium(data.contactPerson, fontWeight: 600)), + DataCell(MyText.bodyMedium(Utils.getDateStringFromDateTime(data.startDate), fontWeight: 600)), + DataCell(MyText.bodyMedium(Utils.getDateStringFromDateTime(data.endDate), fontWeight: 600)), + DataCell(MyText.bodyMedium(data.projectStatusId.toString(), fontWeight: 600)), + ])) .toList()), - ) - ], - ), - ); - } + ) + ], + ), + ); +} } diff --git a/pubspec.lock b/pubspec.lock index 8c8a093..75230af 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -66,7 +66,7 @@ packages: source: hosted version: "1.1.2" collection: - dependency: transitive + dependency: "direct main" description: name: collection sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" diff --git a/pubspec.yaml b/pubspec.yaml index 98a844b..07347eb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -59,6 +59,7 @@ dependencies: syncfusion_flutter_calendar: ^28.2.6 syncfusion_flutter_maps: ^28.1.33 http: ^1.2.2 + collection: ^1.18.0 dev_dependencies: flutter_test: sdk: flutter