Overview
The Seva (service) submission system allows community members to report their service activities. The platform tracks volunteer hours, meals served, community events, and fundraising efforts, aggregating data for impact reporting.
Seva Types
The platform supports two types of seva submissions:
The community seva submission form collects quantifiable service metrics:
app/community-seva/submit-data/page.tsx
const FormSchema = z . object ({
submission_by: z . string (). min ( 1 , "Data Submitter is required" ),
event_name: z . string (). min ( 1 , "Event Name is required" ),
volunteer_hours: z . string ()
. min ( 1 , "Total Volunteer Hours is required" )
. refine (( val ) => {
const num = parseInt ( val )
return ! isNaN ( num ) && num >= 0
}, "Must be a valid number" ),
meals_served: z . string ()
. min ( 1 , "# Meals Served is required" )
. refine (( val ) => {
const num = parseInt ( val )
return ! isNaN ( num ) && num >= 0
}, "Must be a valid number" ),
community_events: z . string ()
. min ( 1 , "# of Community events is required" )
. refine (( val ) => {
const num = parseInt ( val )
return ! isNaN ( num ) && num >= 0
}, "Must be a valid number" ),
funds_raised: z . string ()
. min ( 1 , "$ Funds Raised is required" )
. refine (( val ) => {
const num = parseFloat ( val )
return ! isNaN ( num ) && num >= 0
}, "Must be a valid number" ),
})
type FormData = z . infer < typeof FormSchema >
app/community-seva/submit-data/page.tsx
export default function CommunitySevaSubmitPage () {
const { toast } = useToast ()
const [ isSubmitting , setIsSubmitting ] = useState ( false )
const [ mounted , setMounted ] = useState ( false )
const {
control ,
handleSubmit ,
formState : { errors },
reset
} = useForm < FormData >({
resolver: zodResolver ( FormSchema ),
mode: "onBlur" ,
defaultValues: {
submission_by: "" ,
event_name: "" ,
volunteer_hours: "" ,
meals_served: "" ,
community_events: "" ,
funds_raised: ""
}
})
const onSubmit = async ( data : FormData ) => {
setIsSubmitting ( true )
try {
const dbData = {
submission_by: data . submission_by ,
event_name: data . event_name ,
volunteer_hours: parseInt ( data . volunteer_hours ),
meals_served: parseInt ( data . meals_served ),
community_events: parseInt ( data . community_events ),
funds_raised: parseFloat ( data . funds_raised )
}
const { error } = await supabase
. from ( 'community_seva_records' )
. insert ([ dbData ])
if ( ! error ) {
toast ({
title: "Data submitted successfully!" ,
description: "Jay Shree Swaminarayan" ,
className: "bg-green-500 text-white border-green-400 shadow-xl font-medium" ,
})
reset ()
} else {
toast ({
title: "Submission failed" ,
description: error . message ,
className: "bg-red-500 text-white border-red-400 shadow-xl font-medium" ,
})
}
} catch ( error ) {
toast ({
title: "Submission failed" ,
description: "Please check your connection and try again." ,
className: "bg-red-500 text-white border-red-400 shadow-xl font-medium" ,
})
} finally {
setTimeout (() => setIsSubmitting ( false ), 2000 )
}
}
return (
<>
< div className = "min-h-[calc(100vh+200px)] w-full reg-page-bg page-bg-extend" data-page = "registration" >
< div className = "relative z-10 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 page-bottom-spacing" >
< div className = "text-center page-header-spacing" >
< motion.h1
className = "standard-page-title reg-title"
initial = { { opacity: 0 , y: 30 } }
animate = { { opacity: 1 , y: 0 } }
transition = { { duration: 0.8 , ease: "easeOut" } }
>
Community Seva Data Submission
</ motion.h1 >
< motion.div
className = "flex justify-center px-4 mt-8"
initial = { { opacity: 0 , y: 20 } }
animate = { { opacity: 1 , y: 0 } }
transition = { { duration: 0.8 , delay: 0.2 , ease: "easeOut" } }
>
< p className = "text-center text-base md:text-lg lg:text-xl text-gray-600 leading-relaxed max-w-5xl" >
Submit community seva event data and track our collective impact.
</ p >
</ motion.div >
</ div >
< div className = "max-w-3xl mx-auto" >
< motion.div
className = "relative mt-8"
initial = { { opacity: 0 , y: 50 } }
animate = { { opacity: 1 , y: 0 } }
transition = { { duration: 0.8 , delay: 0.4 , ease: "easeOut" } }
>
< div className = "absolute -inset-4 bg-gradient-to-r from-orange-200/30 via-white/20 to-red-200/30 rounded-[2rem] blur-xl opacity-40 will-change-transform" ></ div >
< div className = "relative" >
< Card className = "reg-card rounded-3xl overflow-hidden relative" >
< CardHeader className = "text-center pb-6 lg:pb-8" >
< CardTitle className = "text-xl lg:text-2xl font-semibold reg-text-primary" > Event Data Form </ CardTitle >
< CardDescription className = "reg-text-secondary text-base" > Please fill in the event details </ CardDescription >
</ CardHeader >
< CardContent >
< form onSubmit = { handleSubmit ( onSubmit ) } className = "space-y-4" >
{ /* Form fields */ }
</ form >
</ CardContent >
</ Card >
</ div >
</ motion.div >
</ div >
</ div >
</ div >
< Toaster />
</>
)
}
Data Submitter Name of person submitting the service data
Event Name Name or description of the service event
Volunteer Hours Total hours contributed by all volunteers
Meals Served Number of meals provided to community members
Community Events Count of community events organized
Funds Raised Dollar amount raised for charitable causes
Validation Rules
Required Fields
All fields are required and cannot be left empty
Numeric Validation
Hours, meals, and events must be valid non-negative integers
Currency Validation
Funds raised must be a valid non-negative decimal number (supports cents)
Inline Feedback
Errors display below each field with reg-error-text styling
Database Schema
CREATE TABLE community_seva_records (
id SERIAL PRIMARY KEY ,
submission_by TEXT NOT NULL ,
event_name TEXT NOT NULL ,
volunteer_hours INTEGER NOT NULL CHECK (volunteer_hours >= 0 ),
meals_served INTEGER NOT NULL CHECK (meals_served >= 0 ),
community_events INTEGER NOT NULL CHECK (community_events >= 0 ),
funds_raised DECIMAL ( 10 , 2 ) NOT NULL CHECK (funds_raised >= 0 ),
created_at TIMESTAMP DEFAULT NOW ()
);
Data Type Conversion
The form converts string inputs to appropriate numeric types:
app/community-seva/submit-data/page.tsx
const dbData = {
submission_by: data . submission_by ,
event_name: data . event_name ,
volunteer_hours: parseInt ( data . volunteer_hours ), // String → Integer
meals_served: parseInt ( data . meals_served ), // String → Integer
community_events: parseInt ( data . community_events ), // String → Integer
funds_raised: parseFloat ( data . funds_raised ) // String → Float
}
Number inputs are validated as strings in Zod schema, then converted to proper numeric types before database insertion to ensure accurate validation messages.
After successful submission, the form automatically resets:
if ( ! error ) {
toast ({
title: "Data submitted successfully!" ,
description: "Jay Shree Swaminarayan" ,
className: "bg-green-500 text-white border-green-400 shadow-xl font-medium" ,
})
reset () // Reset form to default values
}
app/community-seva/submit-data/page.tsx
< button
type = "submit"
disabled = { isSubmitting }
className = "reg-button relative w-full h-14 inline-flex items-center justify-center text-center px-4 py-2 text-base rounded-lg overflow-hidden"
>
< div className = { `absolute inset-0 bg-gradient-to-b from-white/20 to-transparent transform transition-transform duration-500 ${ isSubmitting ? 'translate-y-0' : 'translate-y-full' } ` } ></ div >
< div className = "relative z-10 flex items-center justify-center gap-2" >
{ isSubmitting ? (
<>
< Loader2 className = "w-5 h-5 animate-spin" />
Please wait
</>
) : (
<>
< Send className = "w-5 h-5" />
Submit Data
</>
) }
</ div >
</ button >
Error Handling
Validation Errors
Submission Errors
Network Errors
Inline validation errors appear below each field when blur occurs: { errors . volunteer_hours && (
< p className = "reg-error-text" > { errors . volunteer_hours . message } </ p >
)}
Database errors display via toast notifications: toast ({
title: "Submission failed" ,
description: error . message ,
className: "bg-red-500 text-white border-red-400 shadow-xl font-medium" ,
})
Connection failures show generic error message: toast ({
title: "Submission failed" ,
description: "Please check your connection and try again." ,
className: "bg-red-500 text-white border-red-400 shadow-xl font-medium" ,
})
Reporting & Analytics
Submitted data can be aggregated for impact reports:
-- Total community impact metrics
SELECT
SUM (volunteer_hours) as total_hours,
SUM (meals_served) as total_meals,
SUM (community_events) as total_events,
SUM (funds_raised) as total_funds
FROM community_seva_records;
-- Impact by event
SELECT
event_name,
SUM (volunteer_hours) as hours ,
SUM (meals_served) as meals
FROM community_seva_records
GROUP BY event_name
ORDER BY hours DESC ;
Styling
The seva forms reuse registration theme styles:
reg-page-bg - Background gradient
reg-card - Form card container
reg-input - Input field styling
reg-button - Submit button with animation
reg-label - Form label styling
reg-error-text - Error message styling
The form uses mode: "onBlur" validation, meaning errors only appear after users leave a field. This prevents intrusive validation during typing.