Flutter Workgroup Meetings
Prep WorkgroupMeetings API
Laravel api/WorkgroupMeetingController.php:
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Workgroup;
use App\Models\WorkgroupMeeting;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class WorkgroupMeetingController extends Controller
{
public function index($workgroupId)
{
$user = auth()->user();
$workgroups = Workgroup::where('mngr_email', $user->email)
->get();
// Check if the requested workgroup belongs to the authenticated user
$requestedWorkgroup = $workgroups->firstWhere('id', $workgroupId);
if (!$requestedWorkgroup) {
return response()->json(['error' => 'Unauthorized'], 403);
}
$workgroupMeetings = WorkgroupMeeting::where('workgroup_id', $workgroupId)->get();
return response()->json($workgroupMeetings);
}
}
Laravel routes/api.php:
...
use App\Http\Controllers\Api\WorkgroupMeetingController;
Route::middleware('auth:sanctum')->group(function () {
Route::get('workgroup/{workgroup_id}/meeting', [WorkgroupMeetingController::class, 'index']);
});
...
Edit WorkgroupMeetings Screen
File-> lib/modules/workgroupmeetings.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:hive/hive.dart';
class WorkgroupMeetingsScreen extends StatefulWidget {
final dynamic workgroup;
const WorkgroupMeetingsScreen({Key? key, required this.workgroup})
: super(key: key);
@override
_WorkgroupMeetingsScreenState createState() =>
_WorkgroupMeetingsScreenState();
}
class _WorkgroupMeetingsScreenState extends State<WorkgroupMeetingsScreen> {
List<dynamic> _meetings = [];
final Box _boxUser = Hive.box("user");
bool _isLoading = true;
@override
void initState() {
super.initState();
_fetchMeetings();
}
Future<void> _fetchMeetings() async {
final url =
'https://demo.razzi.my/spotnet/public/api/workgroup/${widget.workgroup['id']}/meeting';
final authToken = await _boxUser.get('user_token');
try {
final response = await http.get(
Uri.parse(url),
headers: {
'Authorization': 'Bearer $authToken',
'Content-Type': 'application/json',
},
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body) as List;
setState(() {
_meetings = data;
_isLoading = false;
});
} else {
setState(() {
_isLoading = false;
});
// Handle error
print('Error fetching meetings: ${response.statusCode}');
}
} catch (e) {
setState(() {
_isLoading = false;
});
// Handle network error
print('Error fetching meetings: $e');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Meetings for ${widget.workgroup['name']}'),
actions: [
ElevatedButton(
onPressed: () {
// Navigate to the "Create Meeting" screen
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => CreateMeetingScreen(
workgroup: widget.workgroup,
))).then((_) {
// This block runs when you have come back to the 1st Page from 2nd.
_fetchMeetings();
});
},
style: ElevatedButton.styleFrom(
backgroundColor: Color.fromARGB(
255, 122, 192, 245), // Set the background color to red
foregroundColor: Colors.white, // Set the font color to white
padding:
const EdgeInsets.all(8.0), // Adjust the padding as needed
),
child: const Icon(Icons.add),
),
],
),
body: _isLoading
? const Center(child: CircularProgressIndicator())
: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: ListView.builder(
itemCount: _meetings.length,
itemBuilder: (context, index) {
final meeting = _meetings[index];
return ListTile(
leading: IconButton(
icon: const Icon(Icons.info),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) =>
MeetingDetailsScreen(meeting: meeting)))
.then((_) {
// This block runs when you have come back to the 1st Page from 2nd.
_fetchMeetings();
});
},
),
title: Text('Description: ${meeting['desn']}'),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Reference: ${meeting['refn']}'),
Text('Location: ${meeting['locn']}'),
Text(
'Start Date: ${DateTime.fromMillisecondsSinceEpoch(meeting['estartdate'] * 1000).toString()}'),
Text('Attendees: ${meeting['attd']}'),
],
),
trailing: IconButton(
icon: const Icon(Icons.chevron_right),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) =>
MeetingDetailsScreen(meeting: meeting),
),
).then((_) {
// This block runs when you have come back to the 1st Page from 2nd.
_fetchMeetings();
});
},
),
);
},
),
),
);
}
}
class CreateMeetingScreen extends StatefulWidget {
final dynamic workgroup;
const CreateMeetingScreen({Key? key, required this.workgroup})
: super(key: key);
@override
_CreateMeetingScreenState createState() => _CreateMeetingScreenState();
}
class _CreateMeetingScreenState extends State<CreateMeetingScreen> {
// Implement the logic for creating a new meeting
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MeetingDetailsScreen extends StatefulWidget {
final dynamic meeting;
const MeetingDetailsScreen({Key? key, required this.meeting})
: super(key: key);
@override
_MeetingDetailsScreenState createState() => _MeetingDetailsScreenState();
}
class _MeetingDetailsScreenState extends State<MeetingDetailsScreen> {
// Implement the logic for displaying the details of a meeting
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
At the moment MeetingDetailsScreen and CreateMeetingScreen are just stub classes.