From 0a1250dfd289d322275c874a1082c93d5f0189f5 Mon Sep 17 00:00:00 2001 From: drake Date: Wed, 12 Jun 2024 14:28:13 -0500 Subject: [PATCH] API Listing half-rewrite --- fbla-api/lib/fbla_api.dart | 152 ++++++++++++++++++++----- fbla_ui/lib/pages/business_detail.dart | 52 ++++++++- 2 files changed, 175 insertions(+), 29 deletions(-) diff --git a/fbla-api/lib/fbla_api.dart b/fbla-api/lib/fbla_api.dart index 3a79eac..0769ec0 100644 --- a/fbla-api/lib/fbla_api.dart +++ b/fbla-api/lib/fbla_api.dart @@ -22,32 +22,33 @@ enum BusinessType { other, } +enum JobType { cashier, server, mechanic } + class Business { int id; String name; String description; - BusinessType type; - String website; - String contactName; - String contactEmail; - String contactPhone; - String notes; - String locationName; - String locationAddress; + BusinessType? type; + String? website; + String? contactName; + String? contactEmail; + String? contactPhone; + String? notes; + String? locationName; + String? locationAddress; - Business({ - required this.id, - required this.name, - required this.description, - required this.type, - required this.website, - required this.contactName, - required this.contactEmail, - required this.contactPhone, - required this.notes, - required this.locationName, - required this.locationAddress, - }); + Business( + {required this.id, + required this.name, + required this.description, + this.type, + this.website, + this.contactName, + this.contactEmail, + this.contactPhone, + this.notes, + this.locationName, + this.locationAddress}); factory Business.fromJson(Map json) { bool typeValid = true; @@ -56,6 +57,7 @@ class Business { } catch (e) { typeValid = false; } + return Business( id: json['id'], name: json['name'], @@ -74,6 +76,22 @@ class Business { } } +class JobListing { + String name; + String description; + JobType type; + String wage; + String link; + + JobListing({ + required this.name, + required this.description, + required this.type, + required this.wage, + required this.link, + }); +} + Future fetchBusinessData() async { final result = await postgres.query(''' SELECT json_agg( @@ -93,9 +111,7 @@ Future fetchBusinessData() async { ) FROM businesses '''); - var encoded = json.encode(result); - var decoded = json.decode(encoded); - encoded = json.encode(decoded[0][0]); + var encoded = json.encode(result[0][0]); return encoded; } @@ -125,12 +141,92 @@ void main() async { headers: {'Access-Control-Allow-Origin': '*'}, ); }); + app.get('/fbla-api/businessdata/overview', (Request request) async { + print('business overview request received'); + + var filters = request.url.queryParameters['filters']?.split(',') ?? + JobType.values.asNameMap().keys; + + // List>>> this is the real type lol + List output = []; + + for (int i = 0; i < filters.length; i++) { + var postgresResult = (await postgres.query(''' + SELECT json_agg( + json_build_object( + 'id', id, + 'name', name, + 'description', description + ) + ) FROM public.businesses WHERE id IN (SELECT id FROM public.listings WHERE type='${filters.elementAt(i)}') + '''))[0][0]; + + if (postgresResult != null) { + output.add({filters.elementAt(i): postgresResult}); + } + } + + return Response.ok( + json.encode(output), + headers: { + 'Access-Control-Allow-Origin': '*', + 'Content-Type': 'text/plain' + }, + ); + }); + app.get('/fbla-api/businessdata/business/', + (Request request, String business) async { + print('idividual business data request received'); + + var result = (await postgres.query(''' + SELECT + json_build_object( + 'id', b.id, + 'name', b.name, + 'description', b.description, + 'type', b.type, + 'website', b.website, + 'contactName', b."contactName", + 'contactEmail', b."contactEmail", + 'contactPhone', b."contactPhone", + 'notes', b.notes, + 'locationName', b."locationName", + 'locationAddress', b."locationAddress", + 'listings', + json_agg( + json_build_object( + 'id', l.id, + 'name', l.name, + 'description', l.description, + 'type', l.type, + 'wage', l.wage, + 'link', l.link + ) + ) + ) + FROM businesses b + LEFT JOIN listings l ON b.id = l.business_id + WHERE b.id = $business + GROUP BY b.id; + '''))[0][0]; + + return Response.ok( + json.encode(result), + headers: { + 'Access-Control-Allow-Origin': '*', + 'Content-Type': 'text/plain' + }, + ); + }); app.get('/fbla-api/businessdata', (Request request) async { print('business data request received'); final output = await fetchBusinessData(); return Response.ok( output.toString(), - headers: {'Access-Control-Allow-Origin': '*'}, + headers: { + 'Access-Control-Allow-Origin': '*', + 'Content-Type': 'text/plain' + }, ); }); app.get('/fbla-api/logos/', (Request request, String logoId) { @@ -159,7 +255,7 @@ void main() async { await postgres.query(''' INSERT INTO businesses (name, description, type, website, "contactName", "contactPhone", "contactEmail", notes, "locationName", "locationAddress") - VALUES ('${business.name.replaceAll("'", "''")}', '${business.description.replaceAll("'", "''")}', '${business.type.name}', '${business.website}', '${business.contactName.replaceAll("'", "''")}', '${business.contactPhone}', '${business.contactEmail}', '${business.notes.replaceAll("'", "''")}', '${business.locationName.replaceAll("'", "''")}', '${business.locationAddress.replaceAll("'", "''")}') + VALUES ('${business.name.replaceAll("'", "''")}', '${business.description.replaceAll("'", "''")}', '${business.type!.name}', '${business.website!}', '${business.contactName!.replaceAll("'", "''")}', '${business.contactPhone!}', '${business.contactEmail!}', '${business.notes!.replaceAll("'", "''")}', '${business.locationName!.replaceAll("'", "''")}', '${business.locationAddress!.replaceAll("'", "''")}') '''); final dbBusiness = await postgres.query('''SELECT * FROM public.businesses @@ -237,7 +333,7 @@ void main() async { await postgres.query(''' UPDATE businesses SET - name = '${business.name.replaceAll("'", "''").replaceAll("\"", "\"\"")}'::text, description = '${business.description.replaceAll("'", "''").replaceAll("\"", "\"\"")}'::text, website = '${business.website}'::text, type = '${business.type.name}'::text, "contactName" = '${business.contactName.replaceAll("'", "''").replaceAll("\"", "\"\"")}'::text, "contactPhone" = '${business.contactPhone}'::text, "contactEmail" = '${business.contactEmail}'::text, notes = '${business.notes.replaceAll("'", "''").replaceAll("\"", "\"\"")}'::text, "locationName" = '${business.locationName.replaceAll("'", "''").replaceAll("\"", "\"\"")}'::text, "locationAddress" = '${business.locationAddress.replaceAll("'", "''").replaceAll("\"", "\"\"")}'::text WHERE + name = '${business.name.replaceAll("'", "''").replaceAll("\"", "\"\"")}'::text, description = '${business.description.replaceAll("'", "''").replaceAll("\"", "\"\"")}'::text, website = '${business.website!}'::text, type = '${business.type!.name}'::text, "contactName" = '${business.contactName!.replaceAll("'", "''").replaceAll("\"", "\"\"")}'::text, "contactPhone" = '${business.contactPhone!}'::text, "contactEmail" = '${business.contactEmail!}'::text, notes = '${business.notes!.replaceAll("'", "''").replaceAll("\"", "\"\"")}'::text, "locationName" = '${business.locationName!.replaceAll("'", "''").replaceAll("\"", "\"\"")}'::text, "locationAddress" = '${business.locationAddress!.replaceAll("'", "''").replaceAll("\"", "\"\"")}'::text WHERE id = ${business.id}; '''); @@ -445,4 +541,6 @@ void main() async { final server = await io.serve(app, _hostname, _port); print('Serving at http://${server.address.host}:${server.port}'); + + // print((await postgres.query('select testdouble from public.test'))); } diff --git a/fbla_ui/lib/pages/business_detail.dart b/fbla_ui/lib/pages/business_detail.dart index 07fbd8a..d8f2d36 100644 --- a/fbla_ui/lib/pages/business_detail.dart +++ b/fbla_ui/lib/pages/business_detail.dart @@ -26,6 +26,7 @@ class _CreateBusinessDetailState extends State { ), body: ListView( children: [ + // Title, logo, desc, website Card( clipBehavior: Clip.antiAlias, child: Column( @@ -41,8 +42,7 @@ class _CreateBusinessDetailState extends State { ), leading: ClipRRect( borderRadius: BorderRadius.circular(6.0), - child: Image.network( - '$apiAddress/logos/${business.id}', + child: Image.network('$apiAddress/logos/${business.id}', width: 48, height: 48, errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) { @@ -63,6 +63,52 @@ class _CreateBusinessDetailState extends State { ], ), ), + // Available positions + Card( + child: Padding( + padding: const EdgeInsets.only(left: 16.0, top: 8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Available Postitions', + style: const TextStyle( + fontSize: 20, fontWeight: FontWeight.bold), + ), + // Container( + // height: 400, + // width: 300, + ListView( + scrollDirection: Axis.vertical, + shrinkWrap: true, + children: [ + ListTile( + title: Text('Postition 1'), + leading: Icon(Icons.work), + onTap: () { + // launchUrl(Uri.parse('')); + }, + ), + ListTile( + title: Text('Postition 2'), + leading: Icon(Icons.work), + onTap: () { + // launchUrl(Uri.parse('')); + }, + ), + ListTile( + title: Text('Postition 3'), + leading: Icon(Icons.work), + onTap: () { + // launchUrl(Uri.parse('')); + }, + ), + ], + ), + ]), + ), + ), + // Contact info Visibility( visible: (business.contactEmail.isNotEmpty || business.contactPhone.isNotEmpty), @@ -138,6 +184,7 @@ class _CreateBusinessDetailState extends State { ), ), ), + // Location Visibility( child: Card( clipBehavior: Clip.antiAlias, @@ -152,6 +199,7 @@ class _CreateBusinessDetailState extends State { ), ), ), + // Notes Visibility( visible: business.notes.isNotEmpty, child: Card(