A specialized library built on RaptorSheets.Core for gig work and freelance tracking. Provides pre-configured sheets for trips, shifts, expenses, and comprehensive analytics for gig economy workers.
$ dotnet add package RaptorSheets.GigRaptorSheets.Gig is a specialized implementation of RaptorSheets.Core designed for gig work and freelance tracking. It provides pre-configured sheet types, entities, and workflows optimized for managing trips, shifts, expenses, and earnings across multiple gig platforms.
dotnet add package RaptorSheets.Gig
using RaptorSheets.Gig.Managers;
using RaptorSheets.Gig.Enums;
// Initialize manager
var manager = new GoogleSheetManager(credentials, spreadsheetId);
// Create all gig-related sheets
await manager.CreateAllSheets();
// Get your data
var data = await manager.GetSheets();
Create a demo spreadsheet with realistic sample data to explore RaptorSheets.Gig capabilities or set up test environments.
Perfect for new users or demos. Creates all sheets and populates with 30 days of realistic gig data:
var manager = new GoogleSheetManager(credentials, spreadsheetId);
// Creates all sheets and adds sample data
var result = await manager.SetupDemo();
Console.WriteLine("✅ Demo spreadsheet ready!");If you already have sheets created, just add sample data:
// Populate existing sheets with demo data
var result = await manager.PopulateDemoData();
Console.WriteLine($"Added demo data: {result.Shifts.Count} shifts, {result.Trips.Count} trips");Specify custom date ranges for your demo data:
// Last 90 days
await manager.SetupDemo(
startDate: DateTime.Today.AddDays(-90),
endDate: DateTime.Today
);
// Specific quarter
await manager.SetupDemo(
startDate: new DateTime(2024, 1, 1),
endDate: new DateTime(2024, 3, 31)
);
// Full year
await manager.PopulateDemoData(
startDate: new DateTime(2024, 1, 1),
endDate: new DateTime(2024, 12, 31)
);The demo system generates realistic gig economy data:
Shifts - 1-3 per day (85% of days)
Trips - 2-10 per shift
Expenses - 0-2 per day (40% of days)
using Google.Apis.Sheets.v4;
using RaptorSheets.Gig.Managers;
public async Task CreateDemoSpreadsheet()
{
// 1. Create a new Google Spreadsheet
var sheetsService = new SheetsService(/* credentials */);
var spreadsheet = await sheetsService.Spreadsheets.Create(new Spreadsheet
{
Properties = new SpreadsheetProperties { Title = "RaptorGig Demo" }
}).ExecuteAsync();
var spreadsheetId = spreadsheet.SpreadsheetId;
// 2. Set up demo with sample data
var manager = new GoogleSheetManager(credentials, spreadsheetId);
var result = await manager.SetupDemo();
// 3. View your demo
Console.WriteLine($"✅ Demo ready at: https://docs.google.com/spreadsheets/d/{spreadsheetId}");
}"Unable to save data" Error
SetupDemo() for new spreadsheets (creates sheets first)PopulateDemoData() only when sheets already existNo Data Appearing
Track your primary gig work data:
Individual trip/delivery tracking:
Work session management:
Business expense tracking:
Supporting data for efficiency:
Frequently visited locations:
Customer and contact management:
Location categorization:
Geographic organization:
Platform and service tracking:
Trip and work categorization:
Automated reporting and statistics:
Day-by-day performance:
Weekday pattern analysis:
Weekly performance tracking:
Monthly summaries:
Annual performance:
public class TripEntity
{
public string Date { get; set; } = "";
public string StartTime { get; set; } = "";
public string EndTime { get; set; } = "";
public string Duration { get; set; } = "";
public string Service { get; set; } = "";
public string Place { get; set; } = "";
public string Name { get; set; } = "";
public string StartAddress { get; set; } = "";
public string EndAddress { get; set; } = "";
public string EndUnit { get; set; } = "";
public decimal? Pay { get; set; }
public decimal? Tip { get; set; }
public decimal? Bonus { get; set; }
public decimal? Cash { get; set; }
public decimal? Distance { get; set; }
public string OrderNumber { get; set; } = "";
public string Note { get; set; } = "";
// ... additional properties
}public class ShiftEntity
{
public string Date { get; set; } = "";
public string Start { get; set; } = "";
public string Finish { get; set; } = "";
public string Service { get; set; } = "";
public string Active { get; set; } = "";
public string Time { get; set; } = "";
public string Region { get; set; } = "";
public bool? Omit { get; set; }
public string Note { get; set; } = "";
// ... additional properties
}public class ExpenseEntity
{
public string Date { get; set; } = "";
public string Category { get; set; } = "";
public string Description { get; set; } = "";
public decimal? Amount { get; set; }
public decimal? Mileage { get; set; }
public string Receipt { get; set; } = "";
public string Note { get; set; } = "";
// ... additional properties
}public interface IGoogleSheetManager
{
Task<SheetEntity> ChangeSheetData(List<string> sheets, SheetEntity sheetEntity);
Task<SheetEntity> CreateAllSheets();
Task<SheetEntity> CreateSheets(List<string> sheets);
Task<SheetEntity> GetSheet(string sheet);
Task<SheetEntity> GetAllSheets();
Task<SheetEntity> GetSheets(List<string> sheets);
Task<List<PropertyEntity>> GetAllSheetProperties();
Task<List<PropertyEntity>> GetSheetProperties(List<string> sheets);
Task<SheetEntity> SetupDemo(DateTime? startDate = null, DateTime? endDate = null);
Task<SheetEntity> PopulateDemoData(DateTime? startDate = null, DateTime? endDate = null);
}var manager = new GoogleSheetManager("your-access-token", "spreadsheet-id");var credentials = new Dictionary<string, string>
{
["type"] = "service_account",
["private_key_id"] = "key-id",
["private_key"] = "private-key",
["client_email"] = "service@project.iam.gserviceaccount.com",
["client_id"] = "client-id"
};
var manager = new GoogleSheetManager(credentials, "spreadsheet-id");// Create all predefined sheets
var result = await manager.CreateAllSheets();
// Create specific sheets
var specificSheets = new List<string> { "Trips", "Shifts", "Expenses" };
var result = await manager.CreateSheets(specificSheets);
// Check for any issues
foreach (var message in result.Messages)
{
Console.WriteLine($"{message.Level}: {message.Text}");
}// Get all data
var allData = await manager.GetAllSheets();
// Get specific sheet
var tripData = await manager.GetSheet("Trips");
Console.WriteLine($"Found {tripData.Trips.Count} trips");
// Get multiple sheets efficiently
var sheets = new List<string> { "Trips", "Shifts" };
var data = await manager.GetSheets(sheets);
// Access the data
foreach (var trip in data.Trips)
{
Console.WriteLine($"Trip: {trip.Date} - ${trip.Pay} + ${trip.Tip}");
}// Prepare your data
var newTrips = new List<TripEntity>
{
new()
{
Date = "2024-01-15",
StartTime = "09:00",
EndTime = "09:30",
Service = "DoorDash",
Place = "McDonald's",
Pay = 8.50m,
Tip = 3.00m,
Distance = 2.5m,
StartAddress = "123 Restaurant St",
EndAddress = "456 Customer Ave"
}
};
var sheetEntity = new SheetEntity { Trips = newTrips };
// Update the sheet
var result = await manager.ChangeSheetData(["Trips"], sheetEntity);
// Handle results
if (result.Messages.Any(m => m.Level == "Error"))
{
Console.WriteLine("Errors occurred during update:");
foreach (var error in result.Messages.Where(m => m.Level == "Error"))
{
Console.WriteLine($"- {error.Text}");
}
}// Update multiple sheet types at once
var sheetEntity = new SheetEntity
{
Trips = new List<TripEntity> { /* trip data */ },
Shifts = new List<ShiftEntity> { /* shift data */ },
Expenses = new List<ExpenseEntity> { /* expense data */ }
};
var sheetsToUpdate = new List<string> { "Trips", "Shifts", "Expenses" };
var result = await manager.ChangeSheetData(sheetsToUpdate, sheetEntity);// Get detailed sheet properties
var properties = await manager.GetAllSheetProperties();
foreach (var prop in properties)
{
Console.WriteLine($"Sheet: {prop.Name}");
Console.WriteLine($"Headers: {prop.Attributes["Headers"]}");
Console.WriteLine($"Max Row: {prop.Attributes["MaxRow"]}");
Console.WriteLine($"Data Rows: {prop.Attributes["MaxRowValue"]}");
}
// Get properties for specific sheets
var tripProperties = await manager.GetSheetProperties(["Trips"]);var result = await manager.GetSheets();
// Process different message types
foreach (var message in result.Messages)
{
switch (message.Type)
{
case "GET_SHEETS":
Console.WriteLine($"Sheet operation: {message.Text}");
break;
case "CHECK_SHEET":
Console.WriteLine($"Validation: {message.Text}");
break;
case "SAVE_DATA":
Console.WriteLine($"Save operation: {message.Text}");
break;
default:
Console.WriteLine($"General: {message.Text}");
break;
}
}The library automatically validates sheet headers and provides feedback:
// Headers are checked automatically when retrieving data
var data = await manager.GetSheets(["Trips"]);
// Check for header validation messages
var headerIssues = data.Messages
.Where(m => m.Type == "CHECK_SHEET")
.ToList();
if (headerIssues.Any())
{
Console.WriteLine("Header validation issues found:");
foreach (var issue in headerIssues)
{
Console.WriteLine($"- {issue.Text}");
}
}using RaptorSheets.Gig.Managers;
using RaptorSheets.Gig.Entities;
// Initialize manager
var manager = new GoogleSheetManager(credentials, spreadsheetId);
// Record a new shift
var todayShift = new ShiftEntity
{
Date = DateTime.Today.ToString("yyyy-MM-dd"),
Start = "09:00",
Finish = "17:00",
Service = "Multi-platform",
Active = "7:30",
Time = "8:00",
Region = "Downtown",
Note = "Busy lunch rush"
};
// Record trips for the day
var todayTrips = new List<TripEntity>
{
new()
{
Date = DateTime.Today.ToString("yyyy-MM-dd"),
StartTime = "09:15",
EndTime = "09:45",
Service = "UberEats",
Place = "Starbucks",
Pay = 6.50m,
Tip = 2.00m,
Distance = 1.8m,
Duration = "30 min"
},
new()
{
Date = DateTime.Today.ToString("yyyy-MM-dd"),
StartTime = "12:00",
EndTime = "12:25",
Service = "DoorDash",
Place = "Chipotle",
Pay = 8.75m,
Tip = 5.00m,
Distance = 2.2m,
Duration = "25 min"
}
};
// Record expenses
var todayExpenses = new List<ExpenseEntity>
{
new()
{
Date = DateTime.Today.ToString("yyyy-MM-dd"),
Category = "Fuel",
Description = "Gas fill-up",
Amount = 45.00m,
Mileage = 250
}
};
// Update all data at once
var sheetEntity = new SheetEntity
{
Shifts = [todayShift],
Trips = todayTrips,
Expenses = todayExpenses
};
var result = await manager.ChangeSheetData(
["Shifts", "Trips", "Expenses"],
sheetEntity
);
// Report results
Console.WriteLine($"Updated {todayTrips.Count} trips, 1 shift, {todayExpenses.Count} expenses");
foreach (var message in result.Messages)
{
Console.WriteLine($"[{message.Level}] {message.Text}");
}// Get weekly data for analysis
var weekData = await manager.GetSheets(["Trips", "Shifts", "Expenses", "Weekly"]);
// Calculate weekly totals
var weekTrips = weekData.Trips.Where(t => IsCurrentWeek(t.Date)).ToList();
var totalEarnings = weekTrips.Sum(t => (t.Pay ?? 0) + (t.Tip ?? 0) + (t.Bonus ?? 0));
var totalDistance = weekTrips.Sum(t => t.Distance ?? 0);
var totalTrips = weekTrips.Count;
var weekExpenses = weekData.Expenses.Where(e => IsCurrentWeek(e.Date)).ToList();
var totalExpenses = weekExpenses.Sum(e => e.Amount ?? 0);
Console.WriteLine($"Week Summary:");
Console.WriteLine($"- Trips: {totalTrips}");
Console.WriteLine($"- Earnings: ${totalEarnings:F2}");
Console.WriteLine($"- Distance: {totalDistance:F1} miles");
Console.WriteLine($"- Expenses: ${totalExpenses:F2}");
Console.WriteLine($"- Net: ${totalEarnings - totalExpenses:F2}");
bool IsCurrentWeek(string dateString)
{
if (DateTime.TryParse(dateString, out var date))
{
var startOfWeek = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek);
return date >= startOfWeek && date < startOfWeek.AddDays(7);
}
return false;
}// Import data from CSV or other sources
var csvTrips = ReadTripsFromCsv("trips.csv"); // Your CSV reading logic
var tripEntities = csvTrips.Select(csvTrip => new TripEntity
{
Date = csvTrip.Date,
StartTime = csvTrip.StartTime,
EndTime = csvTrip.EndTime,
Service = csvTrip.Platform,
Pay = csvTrip.Earnings,
Tip = csvTrip.Tips,
Distance = csvTrip.Miles,
// ... map other fields
}).ToList();
// Batch import - the library handles efficient API usage
var batchSize = 100; // Process in batches
for (int i = 0; i < tripEntities.Count; i += batchSize)
{
var batch = tripEntities.Skip(i).Take(batchSize).ToList();
var batchEntity = new SheetEntity { Trips = batch };
var result = await manager.ChangeSheetData(["Trips"], batchEntity);
Console.WriteLine($"Imported batch {i/batchSize + 1}: {batch.Count} trips");
// Respect API rate limits
await Task.Delay(1000);
}// Good: Update multiple sheets at once
var result = await manager.ChangeSheetData(
["Trips", "Shifts", "Expenses"],
sheetEntity
);
// Avoid: Multiple separate calls
await manager.ChangeSheetData(["Trips"], new SheetEntity { Trips = trips });
await manager.ChangeSheetData(["Shifts"], new SheetEntity { Shifts = shifts });
await manager.ChangeSheetData(["Expenses"], new SheetEntity { Expenses = expenses });// Validate data before sending to sheets
bool IsValidTrip(TripEntity trip)
{
return !string.IsNullOrEmpty(trip.Date) &&
!string.IsNullOrEmpty(trip.Service) &&
trip.Pay.HasValue &&
trip.Pay.Value >= 0;
}
var validTrips = tripList.Where(IsValidTrip).ToList();
if (validTrips.Count != tripList.Count)
{
Console.WriteLine($"Filtered out {tripList.Count - validTrips.Count} invalid trips");
}// Implement retry logic for important operations
async Task<SheetEntity> UpdateWithRetry(List<string> sheets, SheetEntity data, int maxRetries = 3)
{
for (int attempt = 1; attempt <= maxRetries; attempt++)
{
try
{
return await manager.ChangeSheetData(sheets, data);
}
catch (Exception ex) when (attempt < maxRetries)
{
Console.WriteLine($"Attempt {attempt} failed: {ex.Message}. Retrying in {attempt * 1000}ms...");
await Task.Delay(attempt * 1000);
}
}
throw new InvalidOperationException($"Failed to update sheets after {maxRetries} attempts");
}Authentication Errors
Header Validation Warnings
Rate Limiting
Data Not Appearing
// Enable detailed logging by examining all messages
var result = await manager.GetSheets();
Console.WriteLine("=== Operation Details ===");
foreach (var message in result.Messages)
{
Console.WriteLine($"[{message.Level}] {message.Type}: {message.Text}");
Console.WriteLine($" Time: {DateTimeOffset.FromUnixTimeSeconds(message.Time):yyyy-MM-dd HH:mm:ss}");
}
Console.WriteLine($"\n=== Data Summary ===");
Console.WriteLine($"Trips: {result.Trips?.Count ?? 0}");
Console.WriteLine($"Shifts: {result.Shifts?.Count ?? 0}");
Console.WriteLine($"Expenses: {result.Expenses?.Count ?? 0}");For Gig-specific issues and questions:
gig