Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 90 additions & 50 deletions apps/mobile/lib/features/register/pages/warga/register_warga.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import 'dart:io';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart' as img;
import 'package:http/http.dart' as http;
import '../../../../models/text_field.dart';
import '../../../../models/dropdown_field.dart';
import '../../../../models/date_picker_field.dart';
import '../../controller/controller_warga.dart';

class RegisterWargaPage extends StatefulWidget {
Expand All @@ -15,57 +13,90 @@ class RegisterWargaPage extends StatefulWidget {

class _RegisterWargaPageState extends State<RegisterWargaPage> {
final vars = RegisterWargaVariables();
File? ktpImage;
bool isLoading = false;

Future<void> pickImage() async {
final picker = img.ImagePicker();
Future<void> submitRegister() async {
// Validasi form
if (vars.namaC.text.isEmpty ||
vars.emailC.text.isEmpty ||
vars.passwordC.text.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Harap isi semua field")),
);
return;
}

showModalBottomSheet(
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(18)),
),
builder: (_) {
return SizedBox(
height: 160,
child: Column(
children: [
const SizedBox(height: 10),
Container(
height: 5,
width: 45,
decoration: BoxDecoration(
color: Colors.grey[400],
borderRadius: BorderRadius.circular(10),
),
),
const SizedBox(height: 20),
],
if (!vars.emailC.text.endsWith('@gmail.com')) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Email harus berakhiran @gmail.com")),
);
return;
}

setState(() {
isLoading = true;
});

try {
final url = "https://apps-jawa-backend.vercel.app/auth/register";
final body = {
"name": vars.namaC.text.trim(),
"email": vars.emailC.text.trim(),
"password": vars.passwordC.text.trim(),
};

final response = await http.post(
Uri.parse(url),
headers: {"Content-Type": "application/json; charset=UTF-8"},
body: jsonEncode(body),
);

print(response.statusCode);
print(response.body);

final respData = jsonDecode(response.body);

if (response.statusCode == 200 || response.statusCode == 201) {
// Gunakan pesan dari backend dan beri key supaya integration test bisa menemukan
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
key: const Key('snackbar_register_success'),
content: Text(respData['message'] ?? "Register berhasil!"),
),
);
},
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text(respData['message'] ?? response.statusCode.toString()),
),
);
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Terjadi kesalahan: $e")),
);
} finally {
setState(() {
isLoading = false;
});
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],

appBar: AppBar(
elevation: 0,
backgroundColor: Colors.cyan[700],
title: const Text(
"Register Warga",
),
title: const Text("Register Warga"),
),

body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
children: [

// **************** CARD FORM ****************
// ================= CARD FORM =================
Container(
padding: const EdgeInsets.all(18),
decoration: BoxDecoration(
Expand All @@ -76,39 +107,42 @@ class _RegisterWargaPageState extends State<RegisterWargaPage> {
color: Colors.black.withOpacity(0.05),
blurRadius: 12,
offset: const Offset(0, 4),
)
),
],
),

child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [

ModernTextField(controller: vars.namaC, label: "Nama Lengkap", prefixIcon: Icons.badge),
ModernTextField(
controller: vars.namaC,
key: const Key('nama_field'),
label: "Nama Lengkap",
prefixIcon: Icons.badge,
),
ModernTextField(
controller: vars.emailC,
key: const Key('email_field'),
label: "Email (harus @gmail)",
prefixIcon: Icons.email,
keyboardType: TextInputType.emailAddress,
),
ModernTextField(
controller: vars.passwordC,
key: const Key('password_field'),
label: "Password",
prefixIcon: Icons.lock,
keyboardType: TextInputType.visiblePassword,
),

],
),
),

const SizedBox(height: 24),

// **************** BUTTON SAVE ****************
// ================= BUTTON SAVE =================
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {},
key: const Key('submit_register_button'),
onPressed: isLoading ? null : submitRegister,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.cyan[700],
padding: const EdgeInsets.symmetric(vertical: 16),
Expand All @@ -117,10 +151,16 @@ class _RegisterWargaPageState extends State<RegisterWargaPage> {
),
elevation: 3,
),
child: const Text(
"Simpan Data",
style: TextStyle(fontSize: 16, color: Colors.white, fontWeight: FontWeight.w600),
),
child: isLoading
? const CircularProgressIndicator(color: Colors.white)
: const Text(
"Simpan Data",
style: TextStyle(
fontSize: 16,
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
),
),
],
Expand Down
51 changes: 51 additions & 0 deletions apps/mobile/test/integration_test/register_flow_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:flutter/material.dart';
import 'package:mockito/mockito.dart';
import 'package:http/http.dart' as http;
import 'package:http/testing.dart';
import 'package:jawara/features/register/pages/warga/register_warga.dart';

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

testWidgets('E2E Register Warga Flow with mocked HTTP', (WidgetTester tester) async {
// Buat MockClient
final mockClient = MockClient((request) async {
if (request.url.toString().contains('/auth/register')) {
return http.Response(
jsonEncode({
"message": "Register berhasil, silakan lengkapi profil & data keluarga",
"user": {"id": 12, "name": "John Doe", "email": "john@gmail.com", "account_status": "PENDING"}
}),
201,
headers: {"Content-Type": "application/json"},
);
}
return http.Response('Not Found', 404);
});

// Pump halaman RegisterWargaPage dengan dependency injection
await tester.pumpWidget(MaterialApp(
home: RegisterWargaPage(), // pastikan page bisa menerima client
));
await tester.pumpAndSettle();

// Isi form
await tester.enterText(find.byKey(const Key('nama_field')), 'John Doe');
await tester.enterText(find.byKey(const Key('email_field')), 'john@gmail.com');
await tester.enterText(find.byKey(const Key('password_field')), '123456');
await tester.pumpAndSettle();

// Klik submit
final findSubmitButton = find.byKey(const Key('submit_register_button'));
await tester.tap(findSubmitButton);
await tester.pump();
await tester.pump(const Duration(seconds: 1));

// Cek SnackBar muncul
expect(find.byType(SnackBar), findsOneWidget);
expect(find.textContaining('Register berhasil'), findsOneWidget);
});
}
Loading