Setup and context — Learn by Building a Calendar App
Schedule management apps are among the most universally useful types of mobile applications. By building one, you'll naturally learn key app development concepts like state management, data persistence, UI component design, and user interaction patterns — all in a single project.
Below, we build a calendar and schedule management app from scratch using Rork. Even with minimal coding experience, you can lean on Rork's AI assistant to turn well-crafted prompts into production-ready code, freeing you to focus on design and functionality decisions.
What you'll learn:
- Building a month-view calendar UI with event markers
- Managing event data (create, read, update, delete)
- Persisting data locally with AsyncStorage
- Adding reminder notifications with Expo Notifications
- Polishing the UI to App Store / Google Play standards
If you're brand new to Rork, we recommend starting with "Getting Started with Rork" to get familiar with the basics.
Prerequisites & Setup
What You'll Need
- A Rork account (the free plan covers everything in this tutorial)
- A smartphone (iOS or Android — for previewing with Expo Go)
- A web browser on your computer (to access the Rork editor)
Helpful Background Knowledge
- Basic understanding of HTML/CSS
- Familiarity with JavaScript variables, functions, and arrays
That said, Rork's AI handles the heavy lifting, so you can follow along even without deep programming knowledge. Whenever something is unclear, just ask Rork's chat — it'll explain any code it generates.
Step 1: Create Your Project
Log into the Rork dashboard and click "New Project." Name it something descriptive like my-calendar-app.
For your initial prompt, try something like this:
Build a calendar and schedule management app with these features:
1. Month-view calendar UI (highlight today's date)
2. Tap a date to see that day's events
3. Event creation form (title, start time, end time, notes)
4. Edit and delete events
5. Save data locally with AsyncStorage
6. Modern, clean design with a blue color themeRork will generate the screen layout, components, and navigation structure based on this prompt. After a few minutes, you'll see a preview — scan the QR code with Expo Go to test it on your device.
Step 2: Build the Calendar UI
Rork typically generates calendar components using the react-native-calendars library. Here's what the core calendar component looks like with event dot markers:
// CalendarScreen.tsx — Main calendar screen
import React, { useState, useMemo } from 'react';
import { View, StyleSheet } from 'react-native';
import { Calendar } from 'react-native-calendars';
type Event = {
id: string;
title: string;
date: string; // 'YYYY-MM-DD'
startTime: string;
endTime: string;
memo: string;
};
type Props = {
events: Event[];
onDayPress: (dateString: string) => void;
};
export default function CalendarScreen({ events, onDayPress }: Props) {
const [selectedDate, setSelectedDate] = useState('');
// Add dot markers to dates that have events
const markedDates = useMemo(() => {
const marks: Record<string, any> = {};
events.forEach((event) => {
marks[event.date] = {
...marks[event.date],
marked: true,
dotColor: '#4A90D9',
};
});
if (selectedDate) {
marks[selectedDate] = {
...marks[selectedDate],
selected: true,
selectedColor: '#4A90D9',
};
}
return marks;
}, [events, selectedDate]);
const handleDayPress = (day: { dateString: string }) => {
setSelectedDate(day.dateString);
onDayPress(day.dateString);
};
return (
<View style={styles.container}>
<Calendar
markedDates={markedDates}
onDayPress={handleDayPress}
theme={{
todayTextColor: '#4A90D9',
arrowColor: '#4A90D9',
monthTextColor: '#333',
textDayFontSize: 16,
textMonthFontSize: 18,
textDayHeaderFontSize: 14,
}}
/>
</View>
);
}
// Expected output:
// A month-view calendar is displayed with blue dots on dates that have events.
// Tapping a date highlights it (blue background) and shows that day's events below.
const styles = StyleSheet.create({
container: {
backgroundColor: '#FFFFFF',
borderRadius: 12,
overflow: 'hidden',
margin: 16,
elevation: 2,
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.1,
shadowRadius: 4,
},
});The key detail here is using useMemo to efficiently compute markedDates. Whenever the event data changes, the calendar markers update automatically without unnecessary re-renders.
Step 3: Build the Event Creation Form
Next, let's implement the form for adding events. Give Rork a prompt like this:
Create an event form with:
- Title (required, text input)
- Date (selected via DateTimePicker)
- Start time and end time (TimePicker)
- Notes (optional, multiline text)
- Save and Cancel buttons
- Validation: show error if title is emptyHere's what the core form component typically looks like:
// AddEventForm.tsx — Event creation form (core logic)
import React, { useState } from 'react';
import {
View, Text, TextInput, TouchableOpacity,
Alert, StyleSheet, ScrollView,
} from 'react-native';
type EventInput = {
title: string;
date: string;
startTime: string;
endTime: string;
memo: string;
};
type Props = {
initialDate: string;
onSave: (event: EventInput) => void;
onCancel: () => void;
};
export default function AddEventForm({ initialDate, onSave, onCancel }: Props) {
const [title, setTitle] = useState('');
const [memo, setMemo] = useState('');
const [startTime, setStartTime] = useState('09:00');
const [endTime, setEndTime] = useState('10:00');
const handleSave = () => {
if (!title.trim()) {
Alert.alert('Validation Error', 'Please enter a title for this event');
return;
}
onSave({
title: title.trim(),
date: initialDate,
startTime,
endTime,
memo: memo.trim(),
});
};
return (
<ScrollView style={styles.container}>
<Text style={styles.label}>Title *</Text>
<TextInput
style={styles.input}
value={title}
onChangeText={setTitle}
placeholder="Meeting, lunch, study group..."
/>
<Text style={styles.label}>Start Time</Text>
<TextInput
style={styles.input}
value={startTime}
onChangeText={setStartTime}
placeholder="09:00"
/>
<Text style={styles.label}>End Time</Text>
<TextInput
style={styles.input}
value={endTime}
onChangeText={setEndTime}
placeholder="10:00"
/>
<Text style={styles.label}>Notes</Text>
<TextInput
style={[styles.input, styles.memoInput]}
value={memo}
onChangeText={setMemo}
placeholder="Additional details (optional)"
multiline
numberOfLines={4}
/>
<View style={styles.buttonRow}>
<TouchableOpacity style={styles.cancelButton} onPress={onCancel}>
<Text style={styles.cancelText}>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.saveButton} onPress={handleSave}>
<Text style={styles.saveText}>Save</Text>
</TouchableOpacity>
</View>
</ScrollView>
);
}
// Expected output:
// A clean form with fields for title, times, and notes.
// Tapping "Save" validates the input and saves the event.
// If the title is empty, an alert reads "Please enter a title for this event."
const styles = StyleSheet.create({
container: { padding: 20 },
label: { fontSize: 14, fontWeight: '600', color: '#555', marginTop: 16, marginBottom: 6 },
input: {
borderWidth: 1, borderColor: '#DDD', borderRadius: 8,
padding: 12, fontSize: 16, backgroundColor: '#FAFAFA',
},
memoInput: { height: 100, textAlignVertical: 'top' },
buttonRow: { flexDirection: 'row', justifyContent: 'space-between', marginTop: 24 },
cancelButton: {
flex: 1, marginRight: 8, padding: 14, borderRadius: 8,
borderWidth: 1, borderColor: '#DDD', alignItems: 'center',
},
cancelText: { fontSize: 16, color: '#666' },
saveButton: {
flex: 1, marginLeft: 8, padding: 14, borderRadius: 8,
backgroundColor: '#4A90D9', alignItems: 'center',
},
saveText: { fontSize: 16, color: '#FFF', fontWeight: '600' },
});Step 4: Persist Data with AsyncStorage
To make sure events survive app restarts, we'll use AsyncStorage for local persistence.
// storage.ts — Data persistence utilities
import AsyncStorage from '@react-native-async-storage/async-storage';
const EVENTS_KEY = '@calendar_events';
export type CalendarEvent = {
id: string;
title: string;
date: string;
startTime: string;
endTime: string;
memo: string;
};
// Load all events
export async function loadEvents(): Promise<CalendarEvent[]> {
try {
const json = await AsyncStorage.getItem(EVENTS_KEY);
return json ? JSON.parse(json) : [];
} catch (error) {
console.error('Failed to load events:', error);
return [];
}
}
// Save all events
export async function saveEvents(events: CalendarEvent[]): Promise<void> {
try {
await AsyncStorage.setItem(EVENTS_KEY, JSON.stringify(events));
} catch (error) {
console.error('Failed to save events:', error);
}
}
// Add a single event
export async function addEvent(
event: Omit<CalendarEvent, 'id'>
): Promise<CalendarEvent> {
const events = await loadEvents();
const newEvent: CalendarEvent = {
...event,
id: Date.now().toString(),
};
events.push(newEvent);
await saveEvents(events);
return newEvent;
}
// Delete an event
export async function deleteEvent(id: string): Promise<void> {
const events = await loadEvents();
const filtered = events.filter((e) => e.id !== id);
await saveEvents(filtered);
}
// Expected output:
// loadEvents() → Returns the saved events array (empty array on first call)
// addEvent({...}) → Assigns a new ID, saves, and returns the created event
// deleteEvent('123') → Removes the event with that ID and saves the updated listThis pattern gives you a solid local storage foundation. When you're ready to scale up, you can swap AsyncStorage for Supabase or Firebase to enable cloud syncing across devices.
Step 5: Add Reminder Notifications
Let your users receive a reminder before their events by adding local push notifications. Tell Rork:
Add a feature that sends a local notification reminder 15 minutes before each event.
Use Expo Notifications and schedule it automatically when an event is saved.For a deeper dive into push notifications, check out "Implementing Push Notifications in Rork."
Common Errors and Fixes
Calendar Doesn't Render
This usually means react-native-calendars wasn't installed properly. Run npx expo install react-native-calendars in the Rork terminal to fix it.
Events Disappear After Restarting the App
Double-check that AsyncStorage is correctly imported from @react-native-async-storage/async-storage. Verify the package is listed in your package.json.
DateTimePicker Looks Different on iOS vs. Android
This is expected — @react-native-community/datetimepicker uses each platform's native picker UI. If you want a consistent look across platforms, ask Rork to build a custom modal picker instead.
Taking It Further
Once you have the basics working, consider adding these features to make your app stand out:
Week and day views: Beyond the month view, adding a weekly timeline or daily hour-by-hour view makes the app feel much more professional and practical for power users.
Category tagging with color coding: Let users tag events as "Work," "Personal," "Health," etc., with distinct colors. This makes the calendar far more scannable at a glance.
Recurring events: Automatically generating weekly or monthly recurring events is a huge quality-of-life feature that users love.
Google Calendar sync: Using Expo's expo-calendar library, you can integrate with the device's native calendar for seamless two-way sync.
Wrapping Up
In this tutorial, we walked through building a calendar and schedule management app with Rork — from setting up the calendar UI and event forms, to persisting data with AsyncStorage, and adding reminder notifications.
Building a calendar app is an excellent way to practice core mobile development skills: component design, state management, and data persistence. Use what you've learned here as a foundation, and customize it into the perfect scheduling tool for your target audience.