Agent skill
sikhaid-data
Use when working with data, state management, Firebase, or Firestore in SikhAid project. Covers Svelte stores, data flow patterns, Firebase initialization, Firestore CRUD operations, and data types.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/sikhaid-data
SKILL.md
SikhAid Data & State Management
State Management Architecture
Svelte Stores
Pattern: Reactive stores for client-side state management
Store Types Used:
writable()- Read/write stores for component state- No derived stores currently
- No custom stores (plain writable stores)
Store Locations:
src/lib/stores/
├── donation.ts # Donation amount state
├── contact.ts # Contact form submissions
├── volunteering.ts # Volunteer form submissions
└── csr.ts # CSR partnership submissions
Store Patterns
1. Donation Store
File: src/lib/stores/donation.ts
Purpose: Manage selected donation amount across components
import { writable } from 'svelte/store';
export const selectedAmount = writable<number>(0);
export function setDonationAmount(amount: number) {
selectedAmount.set(amount);
// Side effect: scroll to payment form
setTimeout(() => {
const paymentSection = document.getElementById('payment-form');
paymentSection?.scrollIntoView({ behavior: 'smooth' });
}, 100);
}
Usage:
<script lang="ts">
import { selectedAmount, setDonationAmount } from '$lib/stores/donation';
// Read value with $ prefix
$: amount = $selectedAmount;
// Write value
function selectAmount(value: number) {
setDonationAmount(value);
}
</script>
<div>Selected: ₹{$selectedAmount}</div>
<button on:click={() => selectAmount(1000)}>₹1,000</button>
2. Contact Submissions Store
File: src/lib/stores/contact.ts
Purpose: Store contact form submissions (in-memory and Firestore)
import { writable } from 'svelte/store';
export interface ContactSubmission {
name: string;
email: string;
phone: string;
subject: string;
message: string;
timestamp: number;
}
export const contactSubmissions = writable<ContactSubmission[]>([]);
export function addContactSubmission(submission: ContactSubmission) {
contactSubmissions.update(submissions => {
return [...submissions, submission];
});
}
3. Volunteering Store
File: src/lib/stores/volunteering.ts
Purpose: Store volunteer applications
export interface VolunteerSubmission {
fullName: string;
email: string;
mobile: string;
gender: string;
address: string;
opportunity: string;
durationMonths: number;
durationYears: number;
startDate: string;
about: string;
timestamp: number;
}
export const volunteerSubmissions = writable<VolunteerSubmission[]>([]);
4. CSR Store
File: src/lib/stores/csr.ts
Purpose: Store CSR partnership inquiries
export interface CSRSubmission {
companyName: string;
contactPerson: string;
email: string;
phone: string;
companySize: string;
interests: string[];
message: string;
timestamp: number;
}
export const csrSubmissions = writable<CSRSubmission[]>([]);
Data Flow Pattern
Standard Form Submission Flow
1. User fills form
↓
2. Form validation
↓
3. Create submission object with timestamp
↓
4. Update Svelte store (addSubmission)
↓
5. Write to Firestore (addToFirestore)
↓
6. Show success/error feedback
↓
7. Reset form (optional)
Example Flow Implementation
<script lang="ts">
import { addContactSubmission } from '$lib/stores/contact';
import { addContactToFirestore } from '$lib/firestore';
let formData = { name: '', email: '', phone: '', subject: '', message: '' };
let isSubmitting = false;
let successMessage = '';
let errorMessage = '';
async function handleSubmit() {
// 1. Validate
if (!validateForm()) return;
isSubmitting = true;
errorMessage = '';
try {
// 2. Create submission object
const submission = {
...formData,
timestamp: Date.now()
};
// 3. Update store
addContactSubmission(submission);
// 4. Write to Firestore
await addContactToFirestore(submission);
// 5. Success feedback
successMessage = 'Submission received!';
formData = { name: '', email: '', phone: '', subject: '', message: '' };
} catch (error) {
// 6. Error feedback
errorMessage = 'Submission failed. Please try again.';
console.error('❌ Error:', error);
} finally {
isSubmitting = false;
}
}
</script>
Firebase Integration
Firebase Initialization
File: src/lib/firebase.ts
import { initializeApp, type FirebaseApp } from 'firebase/app';
import { getFirestore, type Firestore } from 'firebase/firestore';
import { getAuth, type Auth } from 'firebase/auth';
const firebaseConfig = {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
appId: import.meta.env.VITE_FIREBASE_APP_ID
};
let app: FirebaseApp | null = null;
let db: Firestore | null = null;
let auth: Auth | null = null;
// Browser-only initialization
if (typeof window !== 'undefined') {
try {
app = initializeApp(firebaseConfig);
db = getFirestore(app);
auth = getAuth(app);
console.log('✅ Firebase initialized successfully');
} catch (error) {
console.error('❌ Firebase initialization error:', error);
}
}
export { app, db, auth };
Key Points:
- Browser-only initialization (
typeof window !== 'undefined') - Environment variables for configuration
- Error handling with console logging
- Exports app, db, and auth instances
Firestore Operations
Collections Structure
Firestore Database
├── contact_submissions/
│ └── [auto-generated-id]/
│ ├── name: string
│ ├── email: string
│ ├── phone: string
│ ├── subject: string
│ ├── message: string
│ ├── status: 'new' | 'read' | 'resolved'
│ └── timestamp: Firestore Timestamp
│
├── volunteer_submissions/
│ └── [auto-generated-id]/
│ ├── fullName: string
│ ├── email: string
│ ├── mobile: string
│ ├── opportunity: string
│ ├── status: 'new' | 'read' | 'resolved'
│ └── ...
│
└── csr_submissions/
└── [auto-generated-id]/
├── companyName: string
├── email: string
├── status: 'new' | 'read' | 'resolved'
└── ...
Firestore Functions
File: src/lib/firestore.ts
Add Contact Submission
import { collection, addDoc, Timestamp } from 'firebase/firestore';
import { db } from './firebase';
import type { ContactSubmission } from './stores/contact';
export async function addContactToFirestore(
submission: ContactSubmission
): Promise<string> {
if (!db) throw new Error('Firestore not initialized');
try {
const docRef = await addDoc(collection(db, 'contact_submissions'), {
...submission,
status: 'new',
timestamp: Timestamp.fromMillis(submission.timestamp)
});
console.log('✅ Contact added to Firestore:', docRef.id);
return docRef.id;
} catch (error) {
console.error('❌ Error adding contact:', error);
throw error;
}
}
Get All Submissions
import { collection, getDocs, query, orderBy } from 'firebase/firestore';
export interface FirestoreContactSubmission extends ContactSubmission {
id?: string;
status: 'new' | 'read' | 'resolved';
firestoreTimestamp?: Timestamp;
}
export async function getContactSubmissions(): Promise<FirestoreContactSubmission[]> {
if (!db) throw new Error('Firestore not initialized');
try {
const q = query(
collection(db, 'contact_submissions'),
orderBy('timestamp', 'desc')
);
const querySnapshot = await getDocs(q);
const submissions: FirestoreContactSubmission[] = [];
querySnapshot.forEach((doc) => {
submissions.push({
id: doc.id,
...doc.data() as FirestoreContactSubmission
});
});
console.log(`📊 Fetched ${submissions.length} contact submissions`);
return submissions;
} catch (error) {
console.error('❌ Error fetching submissions:', error);
throw error;
}
}
Update Submission Status
import { doc, updateDoc } from 'firebase/firestore';
export async function updateSubmissionStatus(
collectionName: string,
documentId: string,
status: 'new' | 'read' | 'resolved'
): Promise<void> {
if (!db) throw new Error('Firestore not initialized');
try {
const docRef = doc(db, collectionName, documentId);
await updateDoc(docRef, { status });
console.log(`✅ Updated ${documentId} status to ${status}`);
} catch (error) {
console.error('❌ Error updating status:', error);
throw error;
}
}
Add Volunteer Submission
export async function addVolunteerToFirestore(
submission: VolunteerSubmission
): Promise<string> {
if (!db) throw new Error('Firestore not initialized');
try {
const docRef = await addDoc(collection(db, 'volunteer_submissions'), {
...submission,
status: 'new',
timestamp: Timestamp.fromMillis(submission.timestamp)
});
console.log('✅ Volunteer added:', docRef.id);
return docRef.id;
} catch (error) {
console.error('❌ Error adding volunteer:', error);
throw error;
}
}
Get Volunteer Submissions
export async function getVolunteerSubmissions(): Promise<FirestoreVolunteerSubmission[]> {
if (!db) throw new Error('Firestore not initialized');
try {
const q = query(
collection(db, 'volunteer_submissions'),
orderBy('timestamp', 'desc')
);
const querySnapshot = await getDocs(q);
const submissions: FirestoreVolunteerSubmission[] = [];
querySnapshot.forEach((doc) => {
submissions.push({
id: doc.id,
...doc.data() as FirestoreVolunteerSubmission
});
});
return submissions;
} catch (error) {
console.error('❌ Error fetching volunteers:', error);
throw error;
}
}
CSR Functions (Similar Pattern)
addCSRToFirestore()- Add CSR submissiongetCSRSubmissions()- Get all CSR submissions- Both follow same pattern as contact/volunteer
Static Data Management
Campaigns Data
File: src/lib/data/campaigns.js
Structure:
export const campaigns = [
{
slug: 'langar-aid',
title: 'Langar Aid',
subtitle: 'Free Meals for All',
shortDescription: 'Serving nutritious meals...',
fullDescription: 'Detailed description...',
image: '/images/campaign.jpg',
category: 'hunger-relief',
status: 'ongoing', // 'ongoing' | 'completed' | 'seasonal'
impactStats: [
{ label: 'Meals Served', value: '100,000+', icon: 'mdi:food' }
],
howItWorks: [
{ step: 1, title: 'Step Title', description: 'Step description' }
],
gallery: [
{ src: '/images/gallery1.jpg', alt: 'Description' }
]
},
// More campaigns...
];
Usage:
<script lang="ts">
import { campaigns } from '$lib/data/campaigns';
import type { Campaign } from '$lib/types/campaign';
// Filter campaigns
$: ongoingCampaigns = campaigns.filter(c => c.status === 'ongoing');
// Find by slug
$: campaign = campaigns.find(c => c.slug === 'langar-aid');
</script>
{#each ongoingCampaigns as campaign}
<div>{campaign.title}</div>
{/each}
Blog Data
File: src/lib/data/blogs.js
Structure:
export const blogs = [
{
slug: 'post-slug',
title: 'Blog Post Title',
excerpt: 'Short excerpt...',
content: 'Full blog content...',
author: 'Author Name',
date: '2024-01-15',
image: '/images/blog.jpg',
category: 'community'
},
// More blog posts...
];
TypeScript Types & Interfaces
Campaign Types
File: src/lib/types/campaign.ts
export interface Campaign {
slug: string;
title: string;
subtitle: string;
shortDescription: string;
fullDescription: string;
image: string;
category: string;
status: 'ongoing' | 'completed' | 'seasonal';
impactStats: ImpactStat[];
howItWorks: HowItWorksStep[];
gallery: GalleryImage[];
}
export interface ImpactStat {
label: string;
value: string;
icon: string;
}
export interface HowItWorksStep {
step: number;
title: string;
description: string;
}
export interface GalleryImage {
src: string;
alt: string;
}
Store Types (Defined in store files)
// Contact
export interface ContactSubmission {
name: string;
email: string;
phone: string;
subject: string;
message: string;
timestamp: number;
}
// Volunteer
export interface VolunteerSubmission {
fullName: string;
email: string;
mobile: string;
gender: string;
address: string;
opportunity: string;
durationMonths: number;
durationYears: number;
startDate: string;
about: string;
timestamp: number;
}
// CSR
export interface CSRSubmission {
companyName: string;
contactPerson: string;
email: string;
phone: string;
companySize: string;
interests: string[];
message: string;
timestamp: number;
}
Firestore Extended Types
import type { Timestamp } from 'firebase/firestore';
export interface FirestoreContactSubmission extends ContactSubmission {
id?: string;
status: 'new' | 'read' | 'resolved';
firestoreTimestamp?: Timestamp;
}
export interface FirestoreVolunteerSubmission extends VolunteerSubmission {
id?: string;
status: 'new' | 'read' | 'resolved';
firestoreTimestamp?: Timestamp;
}
export interface FirestoreCSRSubmission extends CSRSubmission {
id?: string;
status: 'new' | 'read' | 'resolved';
firestoreTimestamp?: Timestamp;
}
Data Loading in Components
Loading Firestore Data (Admin Panel)
<script lang="ts">
import { onMount } from 'svelte';
import {
getContactSubmissions,
type FirestoreContactSubmission
} from '$lib/firestore';
let submissions: FirestoreContactSubmission[] = [];
let isLoading = true;
let error = '';
onMount(async () => {
try {
submissions = await getContactSubmissions();
isLoading = false;
} catch (err) {
error = 'Failed to load submissions';
isLoading = false;
}
});
</script>
{#if isLoading}
<div>Loading...</div>
{:else if error}
<div class="text-red-500">{error}</div>
{:else}
{#each submissions as submission}
<div>{submission.name}</div>
{/each}
{/if}
Using Static Data
<script lang="ts">
import { campaigns } from '$lib/data/campaigns';
// No onMount needed - data is already available
$: featuredCampaigns = campaigns.filter(c => c.featured);
</script>
{#each featuredCampaigns as campaign}
<div>{campaign.title}</div>
{/each}
Store Subscription Patterns
Auto-subscribing with $ Prefix
<script lang="ts">
import { selectedAmount } from '$lib/stores/donation';
// Automatic subscription
$: amount = $selectedAmount;
</script>
<div>Amount: ₹{$selectedAmount}</div>
Manual Subscribe/Unsubscribe
<script lang="ts">
import { onDestroy } from 'svelte';
import { contactSubmissions } from '$lib/stores/contact';
let submissions = [];
const unsubscribe = contactSubmissions.subscribe(value => {
submissions = value;
});
onDestroy(() => {
unsubscribe();
});
</script>
Common Data Patterns
Filtering Arrays
<script lang="ts">
import { campaigns } from '$lib/data/campaigns';
let selectedCategory = 'all';
$: filteredCampaigns = selectedCategory === 'all'
? campaigns
: campaigns.filter(c => c.category === selectedCategory);
</script>
Searching
<script lang="ts">
let searchQuery = '';
let campaigns = [...];
$: searchResults = campaigns.filter(campaign =>
campaign.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
campaign.shortDescription.toLowerCase().includes(searchQuery.toLowerCase())
);
</script>
Sorting
<script lang="ts">
let submissions = [...];
let sortBy = 'timestamp'; // 'timestamp' | 'name' | 'status'
$: sortedSubmissions = [...submissions].sort((a, b) => {
if (sortBy === 'timestamp') {
return b.timestamp - a.timestamp; // Newest first
}
if (sortBy === 'name') {
return a.name.localeCompare(b.name);
}
return 0;
});
</script>
When to Use This Skill
- Working with Svelte stores
- Integrating Firebase/Firestore
- Managing form submissions
- Loading or filtering data
- Creating new data types
- Implementing CRUD operations
- Understanding data flow in the app
Related Skills
sikhaid-forms- Form submission patternssikhaid-components- Component state managementsikhaid-overview- Firebase configuration
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?