mirror of
https://github.com/Iconica-Development/flutter_availability.git
synced 2025-05-19 13:13:44 +02:00
feat(flutter_availability_data_interface): add implementation for apply method on availability templates
This commit is contained in:
parent
a8af7fd6ac
commit
6748a2440c
2 changed files with 220 additions and 6 deletions
|
@ -23,6 +23,8 @@ class AvailabilityTemplateModel {
|
||||||
this.id,
|
this.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Automatically parses [templateData] based on the dynamic data map and
|
||||||
|
/// template type.
|
||||||
factory AvailabilityTemplateModel.fromType({
|
factory AvailabilityTemplateModel.fromType({
|
||||||
required String userId,
|
required String userId,
|
||||||
required String name,
|
required String name,
|
||||||
|
@ -63,7 +65,12 @@ class AvailabilityTemplateModel {
|
||||||
/// The specific data for this template
|
/// The specific data for this template
|
||||||
final TemplateData templateData;
|
final TemplateData templateData;
|
||||||
|
|
||||||
|
/// returns the [templateData] in its serialized form
|
||||||
Map<String, dynamic> get rawTemplateData => templateData.toMap();
|
Map<String, dynamic> get rawTemplateData => templateData.toMap();
|
||||||
|
|
||||||
|
/// applies the template to a range of dates
|
||||||
|
List<AvailabilityModel> apply(DateTime start, DateTime end) =>
|
||||||
|
templateData.apply(userId: userId, start: start, end: end);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used as the key for defining week-based templates
|
/// Used as the key for defining week-based templates
|
||||||
|
@ -114,6 +121,7 @@ abstract interface class TemplateData {
|
||||||
/// Applies the current template to all days found between [start] and [end],
|
/// Applies the current template to all days found between [start] and [end],
|
||||||
/// inclusive
|
/// inclusive
|
||||||
List<AvailabilityModel> apply({
|
List<AvailabilityModel> apply({
|
||||||
|
required String userId,
|
||||||
required DateTime start,
|
required DateTime start,
|
||||||
required DateTime end,
|
required DateTime end,
|
||||||
});
|
});
|
||||||
|
@ -147,7 +155,7 @@ class WeekTemplateData implements TemplateData {
|
||||||
if (thursday != null) WeekDay.thursday: thursday,
|
if (thursday != null) WeekDay.thursday: thursday,
|
||||||
if (friday != null) WeekDay.friday: friday,
|
if (friday != null) WeekDay.friday: friday,
|
||||||
if (saturday != null) WeekDay.saturday: saturday,
|
if (saturday != null) WeekDay.saturday: saturday,
|
||||||
if (sunday != null) WeekDay.monday: sunday,
|
if (sunday != null) WeekDay.sunday: sunday,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -188,11 +196,21 @@ class WeekTemplateData implements TemplateData {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<AvailabilityModel> apply({
|
List<AvailabilityModel> apply({
|
||||||
|
required String userId,
|
||||||
required DateTime start,
|
required DateTime start,
|
||||||
required DateTime end,
|
required DateTime end,
|
||||||
}) {
|
}) {
|
||||||
// TODO(Joey): Implement the apply method
|
var dates = _getDatesBetween(start, end);
|
||||||
throw UnimplementedError();
|
|
||||||
|
return [
|
||||||
|
for (var date in dates)
|
||||||
|
if (data.containsKey(WeekDay.fromDateTime(date)))
|
||||||
|
...data[WeekDay.fromDateTime(date)]!.apply(
|
||||||
|
start: date,
|
||||||
|
end: date,
|
||||||
|
userId: userId,
|
||||||
|
),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,11 +263,30 @@ class DayTemplateData implements TemplateData {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<AvailabilityModel> apply({
|
List<AvailabilityModel> apply({
|
||||||
|
required String userId,
|
||||||
required DateTime start,
|
required DateTime start,
|
||||||
required DateTime end,
|
required DateTime end,
|
||||||
}) {
|
}) {
|
||||||
// TODO(Joey): Implement the apply method
|
var dates = _getDatesBetween(start, end);
|
||||||
throw UnimplementedError();
|
|
||||||
|
return [
|
||||||
|
for (var date in dates) ...[
|
||||||
|
AvailabilityModel(
|
||||||
|
userId: userId,
|
||||||
|
startDate: date.mergeTime(startTime),
|
||||||
|
endDate: date.mergeTime(endTime),
|
||||||
|
breaks: [
|
||||||
|
for (var templateBreak in breaks) ...[
|
||||||
|
AvailabilityBreakModel(
|
||||||
|
startTime: date.mergeTime(templateBreak.startTime),
|
||||||
|
endTime: date.mergeTime(templateBreak.endTime),
|
||||||
|
duration: templateBreak.isTight ? null : templateBreak.duration,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -263,3 +300,17 @@ class DayTemplateData implements TemplateData {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<DateTime> _getDatesBetween(DateTime startDate, DateTime endDate) {
|
||||||
|
var diff = endDate.difference(startDate).inDays;
|
||||||
|
return [
|
||||||
|
for (var i = 0; i <= diff; i++) ...[
|
||||||
|
DateTime(startDate.year, startDate.month, startDate.day + i),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
extension _MergeTime on DateTime {
|
||||||
|
DateTime mergeTime(DateTime time) =>
|
||||||
|
DateTime(year, month, day, time.hour, time.minute);
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,126 @@ import "package:flutter_test/flutter_test.dart";
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group("AvailabilityTemplate", () {
|
group("AvailabilityTemplate", () {
|
||||||
|
group("Apply", () {
|
||||||
|
test("applying a week template should generate correct availability", () {
|
||||||
|
DateTime asTime(int hours, [int minutes = 0]) =>
|
||||||
|
DateTime(1, 1, 1, hours, minutes);
|
||||||
|
|
||||||
|
AvailabilityBreakModel createBreak(int startHour) =>
|
||||||
|
AvailabilityBreakModel(
|
||||||
|
startTime: asTime(startHour),
|
||||||
|
endTime: asTime(startHour + 1),
|
||||||
|
duration: const Duration(minutes: 30),
|
||||||
|
);
|
||||||
|
|
||||||
|
DayTemplateData createTemplate(int startHour) => DayTemplateData(
|
||||||
|
startTime: asTime(startHour),
|
||||||
|
endTime: asTime(startHour + 7),
|
||||||
|
breaks: [createBreak(startHour + 3)],
|
||||||
|
);
|
||||||
|
|
||||||
|
var monday = createTemplate(1);
|
||||||
|
var tuesday = createTemplate(2);
|
||||||
|
var wednesday = createTemplate(3);
|
||||||
|
var thursday = createTemplate(4);
|
||||||
|
var friday = createTemplate(5);
|
||||||
|
var saturday = createTemplate(6);
|
||||||
|
var sunday = createTemplate(7);
|
||||||
|
|
||||||
|
var sut = AvailabilityTemplateModel(
|
||||||
|
userId: "",
|
||||||
|
name: "",
|
||||||
|
color: 0,
|
||||||
|
templateType: AvailabilityTemplateType.week,
|
||||||
|
templateData: WeekTemplateData.forDays(
|
||||||
|
monday: monday,
|
||||||
|
tuesday: tuesday,
|
||||||
|
wednesday: wednesday,
|
||||||
|
thursday: thursday,
|
||||||
|
friday: friday,
|
||||||
|
saturday: saturday,
|
||||||
|
sunday: sunday,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
var startOfRangeToApply = DateTime(1999, 1, 1);
|
||||||
|
var endOfRangeToApply = DateTime(2024, 12, 31);
|
||||||
|
|
||||||
|
var availabilities = sut.apply(startOfRangeToApply, endOfRangeToApply);
|
||||||
|
|
||||||
|
AvailabilityModel findAvailabilityByDate(DateTime date) =>
|
||||||
|
availabilities
|
||||||
|
.where((value) => value.startDate.date == date.date)
|
||||||
|
.first;
|
||||||
|
|
||||||
|
var firstDay = startOfRangeToApply;
|
||||||
|
expect(findAvailabilityByDate(firstDay), isA<AvailabilityModel>());
|
||||||
|
|
||||||
|
var lastDay = endOfRangeToApply;
|
||||||
|
expect(findAvailabilityByDate(lastDay), isA<AvailabilityModel>());
|
||||||
|
|
||||||
|
var leapDayMillenial = DateTime(2000, 2, 29);
|
||||||
|
expect(
|
||||||
|
findAvailabilityByDate(leapDayMillenial).matchesTemplate(tuesday),
|
||||||
|
isTrue,
|
||||||
|
);
|
||||||
|
|
||||||
|
var savingsTimeSwitch = DateTime(2020, 10, 25);
|
||||||
|
expect(
|
||||||
|
findAvailabilityByDate(savingsTimeSwitch).matchesTemplate(sunday),
|
||||||
|
isTrue,
|
||||||
|
);
|
||||||
|
|
||||||
|
var dayAfterSavingsTime = DateTime(2020, 10, 26);
|
||||||
|
expect(
|
||||||
|
findAvailabilityByDate(dayAfterSavingsTime).matchesTemplate(monday),
|
||||||
|
isTrue,
|
||||||
|
);
|
||||||
|
|
||||||
|
var aMondayInJuly = DateTime(2024, 7, 8);
|
||||||
|
expect(
|
||||||
|
findAvailabilityByDate(aMondayInJuly).matchesTemplate(monday),
|
||||||
|
isTrue,
|
||||||
|
);
|
||||||
|
|
||||||
|
var aTuesdayInJuly = DateTime(2024, 7, 9);
|
||||||
|
expect(
|
||||||
|
findAvailabilityByDate(aTuesdayInJuly).matchesTemplate(tuesday),
|
||||||
|
isTrue,
|
||||||
|
);
|
||||||
|
|
||||||
|
var aWednesdayInJuly = DateTime(2024, 7, 10);
|
||||||
|
expect(
|
||||||
|
findAvailabilityByDate(aWednesdayInJuly).matchesTemplate(wednesday),
|
||||||
|
isTrue,
|
||||||
|
);
|
||||||
|
|
||||||
|
var aThursdayInJuly = DateTime(2024, 7, 11);
|
||||||
|
expect(
|
||||||
|
findAvailabilityByDate(aThursdayInJuly).matchesTemplate(thursday),
|
||||||
|
isTrue,
|
||||||
|
);
|
||||||
|
|
||||||
|
var aFridayInJuly = DateTime(2024, 7, 12);
|
||||||
|
expect(
|
||||||
|
findAvailabilityByDate(aFridayInJuly).matchesTemplate(friday),
|
||||||
|
isTrue,
|
||||||
|
);
|
||||||
|
|
||||||
|
var aSaturdayInJuly = DateTime(2024, 7, 13);
|
||||||
|
expect(
|
||||||
|
findAvailabilityByDate(aSaturdayInJuly).matchesTemplate(saturday),
|
||||||
|
isTrue,
|
||||||
|
);
|
||||||
|
|
||||||
|
var aSundayInJuly = DateTime(2024, 7, 14);
|
||||||
|
expect(
|
||||||
|
findAvailabilityByDate(aSundayInJuly).matchesTemplate(sunday),
|
||||||
|
isTrue,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
group("Serialization", () {
|
group("Serialization", () {
|
||||||
test("week template should serialize and deserialize correctly", () {
|
test("week template should serialize and deserialize correctly", () {
|
||||||
var baseDate = DateTime(1994, 10, 18, 10, 0);
|
var baseDate = DateTime(1994, 10, 18, 10, 0);
|
||||||
|
@ -62,3 +182,46 @@ void main() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension on AvailabilityModel {
|
||||||
|
bool matchesTemplate(DayTemplateData template) {
|
||||||
|
var startDateMatches = template.startTime.timeMatches(startDate);
|
||||||
|
var endDateMatches = template.endTime.timeMatches(endDate);
|
||||||
|
var breaksMatch = template.breaks.matches(breaks);
|
||||||
|
|
||||||
|
return startDateMatches && endDateMatches && breaksMatch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension on List<AvailabilityBreakModel> {
|
||||||
|
bool matches(List<AvailabilityBreakModel> other) {
|
||||||
|
if (other.length != length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var otherBreak in other) {
|
||||||
|
if (!any((e) => e.matches(otherBreak))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension on AvailabilityBreakModel {
|
||||||
|
bool matches(AvailabilityBreakModel other) {
|
||||||
|
var startTimeMatches = other.startTime.timeMatches(startTime);
|
||||||
|
var endTimeMatches = other.endTime.timeMatches(endTime);
|
||||||
|
var durationMatches = other.duration == duration;
|
||||||
|
|
||||||
|
return startTimeMatches && endTimeMatches && durationMatches;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension on DateTime {
|
||||||
|
DateTime get date => DateTime(year, month, day);
|
||||||
|
|
||||||
|
bool timeMatches(DateTime other) =>
|
||||||
|
other.hour == hour && other.minute == minute;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue