Skip to content

Commit 32de02a

Browse files
authored
Merge pull request #35 from AdianTor/frontend-pages
Add username display and answers under questions #17
2 parents 361d25a + 2a84e94 commit 32de02a

3 files changed

Lines changed: 262 additions & 224 deletions

File tree

app/api_service.dart

Lines changed: 73 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -2,59 +2,60 @@ import 'package:http/http.dart' as http;
22
import 'dart:convert';
33

44
class ApiService {
5-
//main server URL on Fly.io
6-
final String baseUrl = 'https://unstuck.fly.dev/api';
5+
//main server URL on Fly.io
6+
final String baseUrl = 'https://unstuck.fly.dev/api';
77

8-
//Check if server is running
9-
Future<bool> checkServer() async {
10-
try {
11-
final response = await http.get(Uri.parse('$baseUrl/'));
12-
return response.statusCode == 200;
13-
} catch (e) {
14-
return false;
15-
}
16-
}
17-
18-
// == Login ==
19-
20-
Future<bool> registerUser(String username, String password) async {
21-
try {
22-
final response = await http.post(
23-
Uri.parse('$baseUrl/register'),
24-
headers: {'Content-Type': 'application/json'},
25-
body: jsonEncode({
26-
'username': username,
27-
'password': password,
28-
}),
29-
);
30-
return response.statusCode == 201;
31-
} catch (e) {
32-
print('Registration error: $e');
33-
return false;
34-
}
35-
}
36-
37-
Future<bool> loginUser(String username, String password) async {
38-
try {
39-
final response = await http.post(
40-
Uri.parse('$baseUrl/login'),
41-
42-
headers: {'Content-Type': 'application/json'},
43-
body: jsonEncode({
44-
'username': username,
45-
'password': password,
46-
}),
47-
);
48-
return response.statusCode == 200;
49-
} catch (e) {
50-
print('Login error: $e');
51-
return false; // Return false if the request fails
52-
}
53-
}
54-
55-
// == Query and Answer ==
8+
//Check if server is running
9+
Future<bool> checkServer() async {
10+
try {
11+
final response = await http.get(Uri.parse('https://unstuck.fly.dev/'));
12+
return response.statusCode == 200;
13+
} catch (e) {
14+
return false;
15+
}
16+
}
5617

57-
// - Read from the DB -
18+
// == Login ==
19+
20+
Future<bool> registerUser(String username, String password) async {
21+
try {
22+
final response = await http.post(
23+
Uri.parse('$baseUrl/register'),
24+
headers: {'Content-Type': 'application/json'},
25+
body: jsonEncode({
26+
'username': username,
27+
'password': password,
28+
}),
29+
);
30+
return response.statusCode == 201;
31+
} catch (e) {
32+
print('Registration error: $e');
33+
return false;
34+
}
35+
}
36+
37+
Future<String?> loginUser(String username, String password) async {
38+
try {
39+
final response = await http.post(
40+
Uri.parse('$baseUrl/login'),
41+
headers: {'Content-Type': 'application/json'},
42+
body: jsonEncode({
43+
'username': username,
44+
'password': password,
45+
}),
46+
);
47+
if (response.statusCode == 200) {
48+
final data = jsonDecode(response.body);
49+
return data['user']['username'];
50+
}
51+
return null;
52+
} catch (e) {
53+
print('Login error: $e');
54+
return null;
55+
}
56+
}
57+
58+
// == Read from the DB ==
5859

5960
//Get all inquiries from database
6061
Future<List> getInquiries() async {
@@ -83,32 +84,31 @@ class ApiService {
8384
return [];
8485
}
8586
}
86-
87-
//- New entry to DB -
87+
88+
//== New entry to DB ==
8889

8990
//POST - Add an inquiry to the database
9091
Future<bool> addInquiry(String title, String body) async {
91-
try {
92-
final response = await http.post(
93-
Uri.parse('$baseUrl/create-entry'),
94-
headers: {'Content-Type': 'application/json'},
95-
body: jsonEncode({
96-
'resource': 'inquiries',
97-
'data': {
98-
'body': body,
99-
'title': title,
100-
'chosen_answer_id': null,
101-
'is_solved': false,
102-
},
103-
}),
104-
);
105-
106-
return response.statusCode == 200;
107-
} catch (e) {
108-
print('Error: $e');
109-
return false;
92+
try {
93+
final response = await http.post(
94+
Uri.parse('$baseUrl/create-entry'),
95+
headers: {'Content-Type': 'application/json'},
96+
body: jsonEncode({
97+
'resource': 'inquiries',
98+
'data': {
99+
'body': body,
100+
'title': title,
101+
'chosen_answer_id': null,
102+
'is_solved': false,
103+
},
104+
}),
105+
);
106+
return response.statusCode == 200;
107+
} catch (e) {
108+
print('Error: $e');
109+
return false;
110+
}
110111
}
111-
}
112112

113113
//POST - Add an answer to the db
114114
Future<bool> addAnswer(int inquiryId, String answerText) async {
@@ -124,12 +124,10 @@ class ApiService {
124124
},
125125
}),
126126
);
127-
128127
return response.statusCode == 200;
129128
} catch (e) {
130129
print('Error sending answer: $e');
131130
return false;
132131
}
133132
}
134-
135133
}

app/pages/home_page.dart

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import 'ask_page.dart';
44
import 'login_page.dart';
55

66
class HomePage extends StatefulWidget {
7-
const HomePage({super.key});
7+
final String username;
8+
const HomePage({super.key, required this.username});
89

910
@override
1011
State<HomePage> createState() => _HomePageState();
@@ -13,6 +14,7 @@ class HomePage extends StatefulWidget {
1314
class _HomePageState extends State<HomePage> {
1415
final ApiService api = ApiService();
1516
List inquiries = [];
17+
List answers = [];
1618

1719
@override
1820
void initState() {
@@ -21,12 +23,18 @@ class _HomePageState extends State<HomePage> {
2123
}
2224

2325
Future<void> loadData() async {
24-
List data = await api.getInquiries();
26+
List inqData = await api.getInquiries();
27+
List ansData = await api.getAnswers();
2528
setState(() {
26-
inquiries = data;
29+
inquiries = inqData;
30+
answers = ansData;
2731
});
2832
}
2933

34+
List getAnswersForInquiry(int inquiryId) {
35+
return answers.where((a) => a['inquiry_id'] == inquiryId).toList();
36+
}
37+
3038
@override
3139
Widget build(BuildContext context) {
3240
return Scaffold(
@@ -37,18 +45,21 @@ class _HomePageState extends State<HomePage> {
3745
child: ListView(
3846
padding: EdgeInsets.zero,
3947
children: [
40-
const DrawerHeader(
41-
decoration: BoxDecoration(color: Colors.deepPurple),
48+
DrawerHeader(
49+
decoration: const BoxDecoration(color: Colors.deepPurple),
4250
child: Column(
4351
crossAxisAlignment: CrossAxisAlignment.start,
4452
mainAxisAlignment: MainAxisAlignment.end,
4553
children: [
46-
CircleAvatar(
54+
const CircleAvatar(
4755
radius: 30,
4856
child: Icon(Icons.person, size: 30),
4957
),
50-
SizedBox(height: 8),
51-
Text('User Name', style: TextStyle(color: Colors.white, fontSize: 16)),
58+
const SizedBox(height: 8),
59+
Text(
60+
widget.username,
61+
style: const TextStyle(color: Colors.white, fontSize: 16),
62+
),
5263
],
5364
),
5465
),
@@ -86,10 +97,40 @@ class _HomePageState extends State<HomePage> {
8697
itemCount: inquiries.length,
8798
itemBuilder: (context, index) {
8899
final item = inquiries[index];
89-
return ListTile(
90-
leading: const CircleAvatar(child: Icon(Icons.person)),
91-
title: Text(item['title'] ?? 'No title'),
92-
subtitle: Text(item['body'] ?? ''),
100+
final inquiryAnswers = getAnswersForInquiry(item['inquiry_id']);
101+
return Card(
102+
margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
103+
child: Padding(
104+
padding: const EdgeInsets.all(8.0),
105+
child: Column(
106+
crossAxisAlignment: CrossAxisAlignment.start,
107+
children: [
108+
Row(
109+
children: [
110+
const CircleAvatar(
111+
radius: 16,
112+
child: Icon(Icons.person, size: 16),
113+
),
114+
const SizedBox(width: 8),
115+
Text(
116+
item['title'] ?? 'No title',
117+
style: const TextStyle(fontWeight: FontWeight.bold),
118+
),
119+
],
120+
),
121+
const SizedBox(height: 4),
122+
Text(item['body'] ?? ''),
123+
if (inquiryAnswers.isNotEmpty) ...[
124+
const Divider(),
125+
const Text('Answers:', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12)),
126+
...inquiryAnswers.map((answer) => Padding(
127+
padding: const EdgeInsets.only(top: 4, left: 8),
128+
child: Text('• ${answer['body']}'),
129+
)),
130+
],
131+
],
132+
),
133+
),
93134
);
94135
},
95136
),

0 commit comments

Comments
 (0)