refactor: improve build configuration and code organization

- Add build scripts for Android and iOS platforms
- Remove duplicate web implementation (src/web.ts)
- Add proper TypeScript configuration
- Add module documentation to index.ts
- Clean up package.json scripts

This commit improves the project structure and build process by:
1. Adding dedicated build scripts for native platforms
2. Removing redundant web implementation
3. Adding proper TypeScript configuration with strict mode
4. Improving code documentation
5. Organizing package.json scripts

The changes maintain backward compatibility while improving
the development experience and code quality.
This commit is contained in:
Matthew Raymer
2025-03-25 13:13:55 +00:00
parent e946767cba
commit 71e0f297ff
92 changed files with 11523 additions and 69 deletions

121
src/daily-notification.ts Normal file
View File

@@ -0,0 +1,121 @@
/**
* DailyNotification class implementation
* Handles scheduling and managing daily notifications
*/
import { DailyNotificationPlugin, NotificationOptions, NotificationSettings, NotificationEvent } from './definitions';
export class DailyNotification {
private plugin: DailyNotificationPlugin;
private eventListeners: Map<string, Set<EventListener>>;
constructor(plugin: DailyNotificationPlugin) {
this.plugin = plugin;
this.eventListeners = new Map();
this.setupEventListeners();
}
/**
* Schedule a daily notification with the specified options
* @param options Notification options including URL and time
*/
async scheduleDailyNotification(options: NotificationOptions): Promise<void> {
this.validateOptions(options);
await this.plugin.scheduleDailyNotification(options);
}
/**
* Get the last notification that was delivered
*/
async getLastNotification() {
return this.plugin.getLastNotification();
}
/**
* Cancel all scheduled notifications
*/
async cancelAllNotifications(): Promise<void> {
await this.plugin.cancelAllNotifications();
}
/**
* Get the current status of notifications
*/
async getNotificationStatus() {
return this.plugin.getNotificationStatus();
}
/**
* Update notification settings
* @param settings New notification settings
*/
async updateSettings(settings: NotificationSettings): Promise<void> {
this.validateSettings(settings);
await this.plugin.updateSettings(settings);
}
/**
* Add an event listener for notification events
* @param event Event type to listen for
* @param handler Event handler function
*/
on(event: string, handler: EventListener): void {
if (!this.eventListeners.has(event)) {
this.eventListeners.set(event, new Set());
}
this.eventListeners.get(event)?.add(handler);
}
/**
* Remove an event listener
* @param event Event type to remove listener from
* @param handler Event handler function to remove
*/
off(event: string, handler: EventListener): void {
this.eventListeners.get(event)?.delete(handler);
}
private setupEventListeners(): void {
document.addEventListener('notification', (event: Event) => {
const notificationEvent = event as NotificationEvent;
this.eventListeners.get('notification')?.forEach(handler => {
handler(notificationEvent);
});
});
}
private validateOptions(options: NotificationOptions): void {
if (!options.url) {
throw new Error('URL is required');
}
if (!this.isValidTime(options.time)) {
throw new Error('Invalid time format');
}
if (options.timezone && !this.isValidTimezone(options.timezone)) {
throw new Error('Invalid timezone');
}
}
private validateSettings(settings: NotificationSettings): void {
if (settings.time && !this.isValidTime(settings.time)) {
throw new Error('Invalid time format');
}
if (settings.timezone && !this.isValidTimezone(settings.timezone)) {
throw new Error('Invalid timezone');
}
}
private isValidTime(time: string): boolean {
const timeRegex = /^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/;
return timeRegex.test(time);
}
private isValidTimezone(timezone: string): boolean {
try {
Intl.DateTimeFormat(undefined, { timeZone: timezone });
return true;
} catch {
return false;
}
}
}

View File

@@ -1,19 +1,98 @@
/**
* Interface definitions for the Daily Notification plugin
*/
export interface NotificationOptions {
url: string;
time: string;
title?: string;
body?: string;
sound?: boolean;
vibrate?: boolean;
priority?: 'low' | 'normal' | 'high';
retryCount?: number;
retryInterval?: number;
cacheDuration?: number;
headers?: Record<string, string>;
offlineFallback?: boolean;
timezone?: string;
contentHandler?: (response: Response) => Promise<{
title: string;
body: string;
data?: any;
}>;
}
export interface NotificationStatus {
isScheduled: boolean;
nextNotificationTime?: string;
lastNotificationTime?: string;
error?: string;
}
export interface NotificationResponse {
title: string;
body: string;
data?: any;
timestamp: string;
}
export interface NotificationSettings {
time?: string;
sound?: boolean;
vibrate?: boolean;
priority?: 'low' | 'normal' | 'high';
timezone?: string;
}
export interface NotificationEvent extends Event {
detail: {
id: string;
action: string;
data?: any;
};
}
export interface DailyNotificationPlugin {
initialize(options: DailyNotificationOptions): Promise<void>;
checkPermissions(): Promise<PermissionStatus>;
requestPermissions(): Promise<PermissionStatus>;
}
export interface DailyNotificationOptions {
url: string;
notificationTime: string; // "HH:mm" format
title?: string;
body?: string;
}
export interface PermissionStatus {
notifications: PermissionState;
backgroundRefresh?: PermissionState; // iOS only
}
export type PermissionState = 'prompt' | 'prompt-with-rationale' | 'granted' | 'denied';
/**
* Schedule a daily notification with the specified options
*/
scheduleDailyNotification(options: NotificationOptions): Promise<void>;
/**
* Get the last notification that was delivered
*/
getLastNotification(): Promise<NotificationResponse | null>;
/**
* Cancel all scheduled notifications
*/
cancelAllNotifications(): Promise<void>;
/**
* Get the current status of notifications
*/
getNotificationStatus(): Promise<NotificationStatus>;
/**
* Update notification settings
*/
updateSettings(settings: NotificationSettings): Promise<void>;
/**
* Check notification permissions
*/
checkPermissions(): Promise<PermissionStatus>;
/**
* Request notification permissions
*/
requestPermissions(): Promise<PermissionStatus>;
}
export interface PermissionStatus {
notifications: PermissionState;
backgroundRefresh?: PermissionState; // iOS only
}
export type PermissionState = 'prompt' | 'prompt-with-rationale' | 'granted' | 'denied';

View File

@@ -1,5 +1,9 @@
import { registerPlugin } from '@capacitor/core';
/**
* Daily Notification Plugin for Capacitor
* @module DailyNotification
*/
import { registerPlugin } from '@capacitor/core';
import type { DailyNotificationPlugin } from './definitions';
const DailyNotification = registerPlugin<DailyNotificationPlugin>('DailyNotification', {

View File

@@ -1,45 +0,0 @@
import { WebPlugin } from '@capacitor/core';
import type { DailyNotificationPlugin, DailyNotificationOptions, PermissionStatus } from './definitions';
export class DailyNotificationWeb extends WebPlugin implements DailyNotificationPlugin {
async initialize(options: DailyNotificationOptions): Promise<void> {
console.warn('DailyNotification.initialize() is not implemented on web');
return;
}
async checkPermissions(): Promise<PermissionStatus> {
if ('Notification' in window) {
const status = await Notification.permission;
return {
notifications: this.mapWebPermission(status),
};
}
return {
notifications: 'denied',
};
}
async requestPermissions(): Promise<PermissionStatus> {
if ('Notification' in window) {
const status = await Notification.requestPermission();
return {
notifications: this.mapWebPermission(status),
};
}
return {
notifications: 'denied',
};
}
private mapWebPermission(permission: NotificationPermission): PermissionState {
switch (permission) {
case 'granted':
return 'granted';
case 'denied':
return 'denied';
default:
return 'prompt';
}
}
}

117
src/web/index.ts Normal file
View File

@@ -0,0 +1,117 @@
/**
* Web implementation of the Daily Notification plugin
* @module DailyNotificationWeb
*/
import { WebPlugin } from '@capacitor/core';
import { Capacitor } from '@capacitor/core';
import type { DailyNotificationPlugin, NotificationOptions, NotificationSettings, NotificationResponse, NotificationStatus, PermissionStatus, PermissionState } from '../definitions';
export class DailyNotificationWeb extends WebPlugin implements DailyNotificationPlugin {
private lastNotification: NotificationResponse | null = null;
private nextNotificationTime: string | undefined;
private isScheduled: boolean = false;
private lastNotificationTime: string | undefined;
/**
* Initialize the daily notification system for web
* @param options Configuration options for the notification system
*/
async initialize(options: NotificationOptions): Promise<void> {
if (Capacitor.getPlatform() !== 'web') {
throw new Error('This implementation is for web only');
}
// TODO: Implement web-specific initialization
}
async checkPermissions(): Promise<PermissionStatus> {
if (!('Notification' in window)) {
return {
notifications: 'denied' as PermissionState,
};
}
return {
notifications: this.mapWebPermission(Notification.permission),
};
}
async requestPermissions(): Promise<PermissionStatus> {
if (!('Notification' in window)) {
return {
notifications: 'denied' as PermissionState,
};
}
const permission = await Notification.requestPermission();
return {
notifications: this.mapWebPermission(permission),
};
}
private mapWebPermission(permission: NotificationPermission): PermissionState {
switch (permission) {
case 'granted':
return 'granted';
case 'denied':
return 'denied';
default:
return 'prompt';
}
}
async scheduleDailyNotification(options: NotificationOptions): Promise<void> {
if (!('Notification' in window)) {
throw new Error('Notifications not supported in this browser');
}
const permission = await Notification.requestPermission();
if (permission !== 'granted') {
throw new Error('Notification permission denied');
}
// Schedule notification using the browser's notification API
const notification = new Notification(options.title || 'Daily Update', {
body: options.body || 'Your daily update is ready',
});
// Store notification data
this.lastNotification = {
title: options.title || 'Daily Update',
body: options.body || 'Your daily update is ready',
timestamp: new Date().toISOString(),
};
// Update status
this.nextNotificationTime = options.time;
this.isScheduled = true;
}
async getLastNotification(): Promise<NotificationResponse | null> {
return this.lastNotification;
}
async cancelAllNotifications(): Promise<void> {
// No direct way to cancel notifications in web, but we can clear our stored data
this.lastNotification = null;
this.nextNotificationTime = undefined;
this.isScheduled = false;
this.lastNotificationTime = undefined;
}
async getNotificationStatus(): Promise<NotificationStatus> {
return {
isScheduled: this.isScheduled,
nextNotificationTime: this.nextNotificationTime,
lastNotificationTime: this.lastNotificationTime,
};
}
async updateSettings(settings: NotificationSettings): Promise<void> {
// Web implementation might not need to do anything with settings
// but we'll keep track of them
if (settings.time) {
this.nextNotificationTime = settings.time;
}
}
}