Skip to content

Commit

Permalink
Timezone in App (#2581)
Browse files Browse the repository at this point in the history
* added timezone

* formatting

* lint

* Delete .fvmrc

* docs

* Update event_service_test.dart

* Update database_mutation_functions.dart

* Update event_service.dart
  • Loading branch information
pranshugupta54 authored Oct 14, 2024
1 parent 4e11f1b commit b5d02c4
Show file tree
Hide file tree
Showing 7 changed files with 303 additions and 9 deletions.
25 changes: 25 additions & 0 deletions lib/services/database_mutation_functions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:talawa/locator.dart';
import 'package:talawa/models/organization/org_info.dart';
import 'package:talawa/utils/post_queries.dart';
import 'package:talawa/utils/queries.dart';
import 'package:talawa/utils/time_conversion.dart';

/// DataBaseMutationFunctions class provides different services that are under the context of graphQL mutations and queries.
///
Expand Down Expand Up @@ -97,6 +98,13 @@ class DataBaseMutationFunctions {
return await gqlAuthQuery(query, variables: variables);
}
} else if (result.data != null && result.isConcrete) {
// coverage:ignore-start
traverseAndConvertDates(
result.data ?? <String, dynamic>{},
convertUTCToLocal,
splitDateTimeLocal,
);
// coverage:ignore-end
return result;
}
return noData;
Expand All @@ -117,6 +125,11 @@ class DataBaseMutationFunctions {
String mutation, {
Map<String, dynamic>? variables,
}) async {
// coverage:ignore-start
if (variables != null) {
traverseAndConvertDates(variables, convertLocalToUTC, splitDateTimeUTC);
}
// coverage:ignore-end
final MutationOptions options = MutationOptions(
document: gql(mutation),
variables: variables ?? <String, dynamic>{},
Expand Down Expand Up @@ -157,6 +170,11 @@ class DataBaseMutationFunctions {
Map<String, dynamic>? variables,
bool reCall = true,
}) async {
// coverage:ignore-start
if (variables != null) {
traverseAndConvertDates(variables, convertLocalToUTC, splitDateTimeUTC);
}
// coverage:ignore-end
final MutationOptions options = MutationOptions(
document: gql(mutation),
variables: variables ?? <String, dynamic>{},
Expand Down Expand Up @@ -209,6 +227,13 @@ class DataBaseMutationFunctions {
result.exception!,
);
} else if (result.data != null && result.isConcrete) {
// coverage:ignore-start
traverseAndConvertDates(
result.data ?? <String, dynamic>{},
convertUTCToLocal,
splitDateTimeLocal,
);
// coverage:ignore-end
return result;
}
return noData;
Expand Down
138 changes: 138 additions & 0 deletions lib/utils/time_conversion.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import 'package:intl/intl.dart';

/// Combines the given date and time strings into a single string.
///
/// **params**:
/// * `date`: The date string in a valid date format (e.g., 'YYYY-MM-DD').
/// * `time`: The time string in a valid time format (e.g., 'HH:MM:SS').
///
/// **returns**:
/// * `String`: A string that combines the `date` and `time`, separated by a space.
String combineDateTime(String date, String time) {
return '$date $time';
}

/// Splits the given UTC date and time string into separate date and time strings.
///
/// **params**:
/// * `dateTimeStr`: The UTC date and time string in a valid format.
///
/// **returns**:
/// * `Map<String, String>`: A map containing the separate date and time strings.
Map<String, String> splitDateTimeUTC(String dateTimeStr) {
final DateTime dateTime = DateTime.parse(dateTimeStr);
return {
'date': DateFormat('yyyy-MM-dd').format(dateTime),
'time': DateFormat("HH:mm:ss.SSS'Z'").format(dateTime),
};
}

/// Splits the given local date and time string into separate date and time strings.
///
/// **params**:
/// * `dateTimeStr`: The local date and time string in a valid format.
///
/// **returns**:
/// * `Map<String, String>`: A map containing the separate date and time strings.
Map<String, String> splitDateTimeLocal(String dateTimeStr) {
final DateTime dateTime = DateTime.parse(dateTimeStr);
return {
'date': DateFormat('yyyy-MM-dd').format(dateTime),
'time': DateFormat('HH:mm').format(dateTime),
};
}

/// Converts the given UTC time to local time.
///
/// **params**:
/// * `utcTime`: The UTC time string in a valid format.
///
/// **returns**:
/// * `String`: The converted local time string.
String convertUTCToLocal(String utcTime) {
final DateTime dateTime = DateTime.parse(utcTime).toLocal();
return DateFormat('yyyy-MM-ddTHH:mm:ss.SSS').format(dateTime);
}

/// Converts the given local time to UTC time.
///
/// **params**:
/// * `localTime`: The local time string in a valid format.
///
/// **returns**:
/// * `String`: The converted UTC time string.
String convertLocalToUTC(String localTime) {
final DateTime dateTime = DateTime.parse(localTime).toUtc();
return DateFormat("yyyy-MM-ddTHH:mm:ss.SSS'Z'").format(dateTime);
}

/// Traverses a nested map and converts date and time fields to the desired format.
///
/// **params**:
/// * `obj`: The nested map to traverse and convert.
/// * `convertFn`: A function that converts a combined date and time string to the desired format.
/// * `splitFn`: A function that splits a converted date and time string into separate date and time strings.
///
/// **returns**:
/// None
void traverseAndConvertDates(
Map<String, dynamic> obj,
String Function(String) convertFn,
Map<String, String> Function(String) splitFn,
) {
obj.forEach((key, value) {
final pairedFields =
dateTimeFields['pairedFields']?.cast<Map<String, String>>();
if (pairedFields != null) {
for (final field in pairedFields) {
if (key == field['dateField'] && obj.containsKey(field['timeField'])) {
final combinedDateTime = combineDateTime(
obj[field['dateField']] as String,
obj[field['timeField']] as String,
);

final convertedDateTime = convertFn(combinedDateTime);

final splitDateTime = splitFn(convertedDateTime);

obj[field['dateField'] ?? ''] = splitDateTime['date'] ?? '';
obj[field['timeField'] ?? ''] = splitDateTime['time'] ?? '';
}
}
}

if (dateTimeFields['directFields']?.cast<String>().contains(key) ?? false) {
obj[key] = convertFn(value as String);
}

if (value is Map<String, dynamic>) {
traverseAndConvertDates(value, convertFn, splitFn);
} else if (value is List) {
for (final item in value) {
if (item is Map<String, dynamic>) {
traverseAndConvertDates(item, convertFn, splitFn);
}
}
}
});
}

/// Contains information about the date and time fields used for conversion.
const dateTimeFields = {
'directFields': [
'createdAt',
'birthDate',
'updatedAt',
'recurrenceStartDate',
'recurrenceEndDate',
'pluginCreatedBy',
'dueDate',
'completionDate',
'startCursor',
'endCursor',
],
'pairedFields': [
{'dateField': 'startDate', 'timeField': 'startTime'},
{'dateField': 'endDate', 'timeField': 'endTime'},
],
};
Original file line number Diff line number Diff line change
Expand Up @@ -225,12 +225,10 @@ class CreateEventViewModel extends BaseModel {
'organizationId': _currentOrg.id,
'startDate': DateFormat('yyyy-MM-dd').format(eventStartDate),
'endDate': DateFormat('yyyy-MM-dd').format(eventEndDate),
'startTime': isAllDay
? null
: '${DateFormat('HH:mm:ss').format(startTime)}Z',
'endTime': isAllDay
? null
: '${DateFormat('HH:mm:ss').format(endTime)}Z',
'startTime':
isAllDay ? null : DateFormat('HH:mm:ss').format(startTime),
'endTime':
isAllDay ? null : DateFormat('HH:mm:ss').format(endTime),
},
if (isRecurring)
'recurrenceRuleData': {
Expand Down
2 changes: 1 addition & 1 deletion pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ packages:
source: hosted
version: "0.4.1"
clock:
dependency: transitive
dependency: "direct main"
description:
name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ dependencies:

auto_size_text: ^3.0.0
cached_network_image: ^3.4.1
clock: ^1.1.1
connectivity_plus: ^5.0.2
contained_tab_bar_view: ^0.8.0

Expand Down
7 changes: 5 additions & 2 deletions test/service_tests/event_service_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ void main() {
testSetupLocator();
registerServices();
});

group('Test EventService', () {
test('Test editEvent method', () async {
final dataBaseMutationFunctions = locator<DataBaseMutationFunctions>();
Expand Down Expand Up @@ -118,7 +119,7 @@ void main() {
(realInvocation) async => QueryResult(
options: QueryOptions(document: gql(query)),
data: {
'cretedEvent': {
'createdEvent': {
'_id': 'eventId',
'title': 'Test task',
'description': 'Test description',
Expand All @@ -137,12 +138,13 @@ void main() {
when(
dataBaseMutationFunctions.gqlAuthMutation(
EventQueries().registerForEvent(),
variables: {'eventId': 'eventId'},
),
).thenAnswer(
(realInvocation) async => QueryResult(
options: QueryOptions(document: gql(query)),
data: {
'register for an event': {
'registerForEvent': {
'_id': 'eventId',
},
},
Expand Down Expand Up @@ -250,6 +252,7 @@ void main() {
final model = EventService();
expect(model.eventStream, isA<Stream<List<Event>>>());
});

test('Test createVolunteerGroup method', () async {
final dataBaseMutationFunctions = locator<DataBaseMutationFunctions>();
const query = '';
Expand Down
Loading

0 comments on commit b5d02c4

Please sign in to comment.