Skip to content

Support repeatIntervals of minute, hour, day, week, month, and year in addNotificationRequest() #308

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
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
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,8 @@ request is an object containing:
- `body` : The message displayed in the notification alert.
- `badge` The number to display as the app's icon badge. Setting the number to 0 removes the icon badge.
- `fireDate` : The date and time when the system should deliver the notification.
- `repeats` : Sets notification to repeat daily. Must be used with fireDate.
- `repeats` : Sets notification to repeat (default daily). Must be used with fireDate. Use repeatInterval to modify repeat behaviour.
- `repeatInterval`: The interval to repeat as a string. Possible values: `minute`, `hour`, `day`, `week`, `month`, `year` (optional). Default `day` if `repeats` is true.
- `sound` : The sound played when the notification is fired.
- `category` : The category of this notification, required for actionable notifications.
- `isSilent` : If true, the notification will appear without sound.
Expand Down
4 changes: 4 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ export type NotificationRequest = {
* Must be used with fireDate.
*/
repeats?: boolean;
/**
* The interval to repeat as a string. Possible values: minute, hour, day, week, month, year.
*/
repeatInterval?: 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year';
/**
* Sets notification to be silent
*/
Expand Down
110 changes: 80 additions & 30 deletions ios/RCTConvert+Notification.m
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ + (UILocalNotification *)UILocalNotification:(id)json
+ (NSDictionary *)RCTFormatLocalNotification:(UILocalNotification *)notification
{
NSMutableDictionary *formattedLocalNotification = [NSMutableDictionary dictionary];

if (notification.fireDate) {
NSDateFormatter *formatter = [NSDateFormatter new];
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"];
NSString *fireDateString = [formatter stringFromDate:notification.fireDate];
formattedLocalNotification[@"fireDate"] = fireDateString;
}

formattedLocalNotification[@"alertAction"] = RCTNullIfNil(notification.alertAction);
formattedLocalNotification[@"alertTitle"] = RCTNullIfNil(notification.alertTitle);
formattedLocalNotification[@"alertBody"] = RCTNullIfNil(notification.alertBody);
Expand All @@ -93,11 +93,11 @@ @implementation RCTConvert (UNNotificationRequest)
+ (UNNotificationRequest *)UNNotificationRequest:(id)json
{
NSDictionary<NSString *, id> *details = [self NSDictionary:json];

BOOL isSilent = [RCTConvert BOOL:details[@"isSilent"]];
NSString* identifier = [RCTConvert NSString:details[@"id"]];


UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
content.title= [RCTConvert NSString:details[@"title"]];
content.subtitle= [RCTConvert NSString:details[@"subtitle"]];
Expand All @@ -116,14 +116,64 @@ + (UNNotificationRequest *)UNNotificationRequest:(id)json
}

NSDate* fireDate = [RCTConvert NSDate:details[@"fireDate"]];
BOOL repeats = [RCTConvert BOOL:details[@"repeats"]];
NSDateComponents *triggerDate = fireDate ? [[NSCalendar currentCalendar]
components:NSCalendarUnitYear +
NSCalendarUnitMonth + NSCalendarUnitDay +
NSCalendarUnitHour + NSCalendarUnitMinute +
NSCalendarUnitSecond + NSCalendarUnitTimeZone
fromDate:fireDate] : nil;

NSString* repeatInterval = [RCTConvert NSString:details[@"repeatInterval"]];

//For backward compatability with existing request interface.
//If repeats param is set to true and no repeatInterval set then use "day" as the default
BOOL repeatsParam = [RCTConvert BOOL:details[@"repeats"]];
if (repeatsParam && repeatInterval.length == 0) {
repeatInterval = @"day";
}

BOOL repeats = TRUE;
NSDateComponents *triggerDate = nil;

if (fireDate) {
if ([repeatInterval isEqualToString:@"year"]) {
triggerDate = [[NSCalendar currentCalendar]
components:
NSCalendarUnitMonth + NSCalendarUnitDay +
NSCalendarUnitHour + NSCalendarUnitMinute +
NSCalendarUnitSecond + NSCalendarUnitTimeZone
fromDate:fireDate];
} else if ([repeatInterval isEqualToString:@"month"]) {
triggerDate = fireDate ? [[NSCalendar currentCalendar]
components: NSCalendarUnitDay +
NSCalendarUnitHour + NSCalendarUnitMinute +
NSCalendarUnitSecond + NSCalendarUnitTimeZone
fromDate:fireDate] : nil;
} else if ([repeatInterval isEqualToString:@"week"]) {
triggerDate = fireDate ? [[NSCalendar currentCalendar]
components: NSCalendarUnitWeekday +
NSCalendarUnitHour + NSCalendarUnitMinute +
NSCalendarUnitSecond + NSCalendarUnitTimeZone
fromDate:fireDate] : nil;
} else if ([repeatInterval isEqualToString:@"day"]) {
triggerDate = fireDate ? [[NSCalendar currentCalendar]
components:
NSCalendarUnitHour + NSCalendarUnitMinute +
NSCalendarUnitSecond + NSCalendarUnitTimeZone
fromDate:fireDate] : nil;
} else if ([repeatInterval isEqualToString:@"hour"]) {
triggerDate = fireDate ? [[NSCalendar currentCalendar]
components: NSCalendarUnitMinute +
NSCalendarUnitSecond + NSCalendarUnitTimeZone
fromDate:fireDate] : nil;
} else if ([repeatInterval isEqualToString:@"minute"]) {
triggerDate = fireDate ? [[NSCalendar currentCalendar]
components: NSCalendarUnitSecond + NSCalendarUnitTimeZone
fromDate:fireDate] : nil;
} else { //If no valid repeat interval, set repeats to false and create non-repeating trigger date
repeats = FALSE;
triggerDate = [[NSCalendar currentCalendar]
components: NSCalendarUnitYear +
NSCalendarUnitMonth + NSCalendarUnitDay +
NSCalendarUnitHour + NSCalendarUnitMinute +
NSCalendarUnitSecond + NSCalendarUnitTimeZone
fromDate:fireDate];
}
}

UNCalendarNotificationTrigger* trigger = triggerDate ? [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:triggerDate repeats:repeats] : nil;

UNNotificationRequest* notification = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger];
Expand All @@ -136,9 +186,9 @@ + (UNNotificationRequest *)UNNotificationRequest:(id)json
+ (NSDictionary *)RCTFormatUNNotificationRequest:(UNNotificationRequest*)request
{
NSMutableDictionary *formattedRequest = [NSMutableDictionary dictionary];

formattedRequest[@"id"] = RCTNullIfNil(request.identifier);

UNNotificationContent *content = request.content;
formattedRequest[@"title"] = RCTNullIfNil(content.title);
formattedRequest[@"subtitle"] = RCTNullIfNil(content.subtitle);
Expand All @@ -148,7 +198,7 @@ + (NSDictionary *)RCTFormatUNNotificationRequest:(UNNotificationRequest*)request
formattedRequest[@"category"] = RCTNullIfNil(content.categoryIdentifier);
formattedRequest[@"thread-id"] = RCTNullIfNil(content.threadIdentifier);
formattedRequest[@"userInfo"] = RCTNullIfNil(RCTJSONClean(content.userInfo));

if (request.trigger) {
UNCalendarNotificationTrigger* trigger = (UNCalendarNotificationTrigger*)request.trigger;
NSDateFormatter *formatter = [NSDateFormatter new];
Expand Down Expand Up @@ -195,11 +245,11 @@ + (UNNotificationAction *)UNNotificationAction:(id)json
NSDictionary<NSString *, id> *details = [self NSDictionary:json];
NSString* identifier = [RCTConvert NSString:details[@"id"]];
NSString* title = [RCTConvert NSString:details[@"title"]];


UNNotificationActionOptions options = [RCTConvert UNNotificationActionOptions:details[@"options"]];
UNNotificationAction* action = details[@"textInput"] ? [UNTextInputNotificationAction actionWithIdentifier:identifier title:title options:options textInputButtonTitle:details[@"textInput"][@"buttonTitle"] textInputPlaceholder:details[@"textInput"][@"placeholder"]] : [UNNotificationAction actionWithIdentifier:identifier title:title options:options];

return action;
}

Expand All @@ -213,15 +263,15 @@ @implementation RCTConvert (UNNotificationCategory)
+ (UNNotificationCategory *)UNNotificationCategory:(id)json
{
NSDictionary<NSString *, id> *details = [self NSDictionary:json];

NSString* identifier = [RCTConvert NSString:details[@"id"]];
NSMutableArray* actions = [NSMutableArray new];
for (NSDictionary* action in [RCTConvert NSArray:details[@"actions"]]) {
[actions addObject:[RCTConvert UNNotificationAction:action]];
}

UNNotificationCategory* category = [UNNotificationCategory categoryWithIdentifier:identifier actions:actions intentIdentifiers:@[] options:UNNotificationCategoryOptionNone];

return category;
}

Expand All @@ -237,21 +287,21 @@ + (NSDictionary *)RCTFormatUNNotificationResponse:(UNNotificationResponse *)resp
UNNotification* notification = response.notification;
NSMutableDictionary *formattedResponse = [[RCTConvert RCTFormatUNNotification:notification] mutableCopy];
UNNotificationContent *content = notification.request.content;

NSMutableDictionary *userInfo = [content.userInfo mutableCopy];
userInfo[@"userInteraction"] = [NSNumber numberWithInt:1];
userInfo[@"actionIdentifier"] = response.actionIdentifier;

formattedResponse[@"badge"] = RCTNullIfNil(content.badge);
formattedResponse[@"sound"] = RCTNullIfNil(content.sound);
formattedResponse[@"userInfo"] = RCTNullIfNil(RCTJSONClean(userInfo));
formattedResponse[@"actionIdentifier"] = RCTNullIfNil(response.actionIdentifier);

NSString* userText = [response isKindOfClass:[UNTextInputNotificationResponse class]] ? ((UNTextInputNotificationResponse *)response).userText : nil;
if (userText) {
formattedResponse[@"userText"] = RCTNullIfNil(userText);
}

return formattedResponse;
}
@end
Expand All @@ -265,16 +315,16 @@ + (NSDictionary *)RCTFormatUNNotification:(UNNotification *)notification
{
NSMutableDictionary *formattedNotification = [NSMutableDictionary dictionary];
UNNotificationContent *content = notification.request.content;

formattedNotification[@"identifier"] = notification.request.identifier;

if (notification.date) {
NSDateFormatter *formatter = [NSDateFormatter new];
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"];
NSString *dateString = [formatter stringFromDate:notification.date];
formattedNotification[@"date"] = dateString;
}

formattedNotification[@"title"] = RCTNullIfNil(content.title);
formattedNotification[@"subtitle"] = RCTNullIfNil(content.subtitle);
formattedNotification[@"body"] = RCTNullIfNil(content.body);
Expand All @@ -283,7 +333,7 @@ + (NSDictionary *)RCTFormatUNNotification:(UNNotification *)notification
formattedNotification[@"category"] = RCTNullIfNil(content.categoryIdentifier);
formattedNotification[@"thread-id"] = RCTNullIfNil(content.threadIdentifier);
formattedNotification[@"userInfo"] = RCTNullIfNil(RCTJSONClean(content.userInfo));

return formattedNotification;
}

Expand Down
4 changes: 4 additions & 0 deletions js/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ export type NotificationRequest = {|
* Must be used with fireDate.
*/
repeats?: boolean,
/**
* The interval to repeat as a string. Possible values: minute, hour, day, week, month, year.
*/
repeatInterval?: string,
/**
* Sets notification to be silent
*/
Expand Down