Skip to main content
The Spiritual Seva page at /spiritual-seva invites devotees to deepen their faith through a structured, year-long program of personal spiritual practice. In celebration of the Temple’s Rajat Mahotsav, each haribhakt commits to monthly niyams (disciplines) grounded in the four pillars: Dharma, Gnyan, Vairagya, and Bhakti.
Spiritual seva runs over a ten-month period from October 2025 to July 2026. A live checkpoint of individual totals is held on January 1st to celebrate progress and inspire continued dedication.

Monthly spiritual goals

Each devotee is encouraged to complete the following targets every month:
SevaTargetDescription
Malas250Meditational prayer beads
Dhyaan250 minFull body meditation
Pradakshinas250Clockwise devotion around the sihasan
Dandvats250Physical devotion to Lord Swaminarayan
Padyatras25Walks to the Mandir
Upvas25Fast for a full day

Sacred scripture parayans

Devotees are also inspired to complete readings of sacred scriptures. Three parayans are recommended:

Sadachar Sandesh

Teachings of Prem Murti Acharya Swamishree Maharaj. Available in Gujarati and English.

Harignanamrut Kavya

Kirtans composed by Jeevanpran Shree Muktajeevan Swamibapa. Available in Gujarati (4 parts) and English transliteration.

Bapashree ni Vato

Discourses by Jeevanpran Shree Abji Bapashree. Available in Gujarati (2 parts) and English (2 parts).

Submission form

Devotees submit their spiritual seva at /spiritual-seva/submit. The form is defined inline in app/spiritual-seva/submit/page.tsx.
The route /spiritual-seva/submit uses a dedicated page-level form that is separate from the reusable SevaSubmissionForm component in components/organisms/seva-submission-form.tsx. The submit page includes all seva types including Upvas and scripture parayans.

Form fields

FieldRequiredValidation
First nameYesLetters only (/^[A-Za-z]+$/)
Middle nameNoLetters only if provided
Last nameYesLetters only
GhaamYesLetters only
Phone numberYesisValidPhoneNumber() via react-phone-number-input
CountryYesSelector: Australia, Canada, England, India, Kenya, USA
MandalYesDerived from country (dropdown or auto-filled)
Seva typesYes (≥1)Checkbox selection from all 9 seva types (see below)
Count per sevaYesPositive integer for each selected seva type
For India, Australia, Canada, and Kenya, the Mandal field is auto-filled and disabled. For England and USA, a dropdown of specific mandals is shown (e.g., Bolton, London for England; Alabama, California, New Jersey, etc. for USA).

Seva types available

All 9 seva types are available as checkboxes on the submission form:
Seva IDLabel
malasMalas
dhyanDhyan (Minutes)
pradakshinasPradakshinas
dandvatsDandvats
padyatrasPadyatras
sadacharSadachar Sandesh Parayan
harignanamrutHarignanamrut Kavya Parayan
bapashreeBapashree ni Vato Parayan
upvasUpvas

Submission workflow

1

Fill personal details

Enter first name, middle name (optional), last name, ghaam, phone number, country, and mandal.
2

Select seva types

Check one or more seva categories. A numeric input field appears for each checked seva.
3

Enter seva counts

Enter a positive integer for each selected seva type (e.g., 250 Malas, 180 minutes of Dhyan).
4

Submit

Click Submit Seva. The form is validated with Zod before submission. A loading spinner (Loader2) is shown while the request is in flight.
5

Receive confirmation

On success, a green Sonner toast displays: "Seva recorded, {firstName}! Jay Shree Swaminarayan". On failure, a red toast displays the error message.

Zod schema

The full submission form schema from app/spiritual-seva/submit/page.tsx:
app/spiritual-seva/submit/page.tsx
const SubmitFormSchema = z.object({
  firstName: z.string().min(1, "First name is required").regex(/^[A-Za-z]+$/, "First name must contain only letters"),
  middleName: z.string().optional().refine((val) => !val || /^[A-Za-z]+$/.test(val), "Middle name must contain only letters"),
  lastName: z.string().min(1, "Last name is required").regex(/^[A-Za-z]+$/, "Last name must contain only letters"),
  ghaam: z.string().min(1, "Ghaam is required").regex(/^[A-Za-z]+$/, "Ghaam must contain only letters"),
  country: z.string().min(1, "Country is required"),
  mandal: z.string().min(1, "Mandal is required"),
  phoneCountryCode: z.string().min(1, "Phone country code is required"),
  phone: z.string().min(1, "Phone number is required").refine((value) => value && isValidPhoneNumber(value), {
    message: "Invalid phone number",
  }),
  selectedSevas: z.array(z.string()).min(1, "Please select at least one seva type"),
  // Countable seva fields
  malas: z.string().optional(),
  dhyan: z.string().optional(),
  pradakshinas: z.string().optional(),
  dandvats: z.string().optional(),
  padyatras: z.string().optional(),
  upvas: z.string().optional(),
  // Scripture parayan fields
  sadachar: z.string().optional(),
  harignanamrut: z.string().optional(),
  bapashree: z.string().optional(),
}).refine((data) => {
  // All selected seva types must have a positive count
  for (const seva of data.selectedSevas) {
    const count = data[seva as keyof typeof data]
    if (!count || count === "" || parseInt(count as string) <= 0) return false
  }
  return true
}, {
  message: "Please enter valid counts for all selected sevas",
  path: ["selectedSevas"]
})

File upload API

Spiritual seva submissions that include file attachments (photos, documents) use a presigned URL flow to upload directly to Cloudflare R2.

API endpoint

POST /api/generate-upload-urls
The source file for this handler has a typo in its filename: app/api/generate-upload-ursl.ts. It is implemented as a Next.js Pages API route (NextApiRequest / NextApiResponse), not an App Router route handler.

Request body

type RequestBody = {
  submissionId: string;   // UUID from the database row
  eventName: string;      // Used to name the R2 folder
  files: FileMetadata[];  // Array of { name: string; type: string }
  directoryName: string;  // Top-level R2 prefix/folder
}

Response

type ResponsePayload = {
  uploadUrls?: { url: string; key: string; filename: string }[];
  error?: string;
}

Upload flow

1

Request presigned URLs

The client POSTs file metadata (name, MIME type) along with submissionId, eventName, and directoryName to /api/generate-upload-urls.
2

Server generates signed URLs

For each file, the server constructs an R2 key in the format:
{R2_BUCKET_PREFIX}{directoryName}/{submissionId}_{cleanEventName}/{filename}
A PutObjectCommand is created and signed with @aws-sdk/s3-request-presigner. URLs expire in 600 seconds.
3

Client uploads directly to R2

The client performs a PUT request to each presigned URL with the file body and Content-Type header. No files pass through the Next.js server.

Environment variables

VariableDescription
R2_ENDPOINTCloudflare R2 S3-compatible endpoint URL
R2_ACCESS_KEY_IDR2 access key
R2_SECRET_ACCESS_KEYR2 secret key
R2_BUCKET_NAMETarget R2 bucket
R2_BUCKET_PREFIXPath prefix applied to all keys

Toast notifications

The form uses useToast() from hooks/use-toast.ts for feedback:
StateStyleMessage
Successbg-green-500 text-white"Seva recorded, {firstName}! Jay Shree Swaminarayan"
Errorbg-red-500 text-white"Submission failed" + error message

FAQ

The spiritual seva period runs from October 2025 through July 2026, aligned with the lead-up to the Rajat Mahotsav event in late July 2026.
Ghaam is the ancestral village name used within the Swaminarayan community to identify a devotee’s family lineage. It is required for seva record-keeping.
A live review of individual seva totals is conducted on January 1st, serving as a milestone celebration and opportunity to inspire devotees to continue through the remaining months.
Yes. The country selector and mandal dropdown support Australia, Canada, England, India, Kenya, and the USA. Devotees from India, Australia, Canada, and Kenya have their mandal auto-assigned.
No. File uploads are optional. The form can be submitted without attaching any photos or documents.

Build docs developers (and LLMs) love