From 327dadff224dc90d69764c654033ef083cff11e0 Mon Sep 17 00:00:00 2001 From: fISHIE <83373559+WhoIsFishie@users.noreply.github.com> Date: Wed, 28 Jan 2026 15:22:03 +0500 Subject: [PATCH] create petitions added support to create petitions from the website --- .claude/settings.local.json | 3 +- Frontend/README.md | 8 - Frontend/fonts/utheem.ttf | Bin 70292 -> 0 bytes Frontend/index.html | 701 ------------------ Frontend/style.css | 496 ------------- frontend-react/package-lock.json | 54 ++ frontend-react/package.json | 1 + frontend-react/src/App.tsx | 132 +--- frontend-react/src/hooks/usePetition.ts | 14 +- frontend-react/src/lib/api.ts | 68 +- .../src/pages/CreatePetitionPage.tsx | 400 ++++++++++ frontend-react/src/pages/HomePage.tsx | 50 ++ frontend-react/src/pages/PetitionPage.tsx | 123 +++ frontend-react/src/types/petition.ts | 1 + 14 files changed, 715 insertions(+), 1336 deletions(-) delete mode 100644 Frontend/README.md delete mode 100644 Frontend/fonts/utheem.ttf delete mode 100644 Frontend/index.html delete mode 100644 Frontend/style.css create mode 100644 frontend-react/src/pages/CreatePetitionPage.tsx create mode 100644 frontend-react/src/pages/HomePage.tsx create mode 100644 frontend-react/src/pages/PetitionPage.tsx diff --git a/.claude/settings.local.json b/.claude/settings.local.json index ad9f6bf..76f3691 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -5,7 +5,8 @@ "Bash(docker compose:*)", "Bash(chmod:*)", "Bash(tree:*)", - "Bash(./ci-helper:*)" + "Bash(./ci-helper:*)", + "Bash(npm run build:*)" ] } } diff --git a/Frontend/README.md b/Frontend/README.md deleted file mode 100644 index 5a6d952..0000000 --- a/Frontend/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# WPetition - -a very basic and simple frontend to show how easy it is to setup the ui for this - -``` -baseUrl: 'http://localhost:5299' -``` -make sure to edit this for prod pls or it wont work \ No newline at end of file diff --git a/Frontend/fonts/utheem.ttf b/Frontend/fonts/utheem.ttf deleted file mode 100644 index 2f244dcb5448440c6ad0e56d39125074b14fd285..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 70292 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 z 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 MU*@kIuH?u61fWggQ~&?~ diff --git a/Frontend/index.html b/Frontend/index.html deleted file mode 100644 index 10dc094..0000000 --- a/Frontend/index.html +++ /dev/null @@ -1,701 +0,0 @@ - - - - - - Petition Details - - - - - - - - -
-
Loading petition...
- - -
- - - - - - - diff --git a/Frontend/style.css b/Frontend/style.css deleted file mode 100644 index d0375c7..0000000 --- a/Frontend/style.css +++ /dev/null @@ -1,496 +0,0 @@ -@font-face { - font-family: 'Utheem'; - src: url('fonts/utheem.woff') format('woff'), - url('fonts/utheem.ttf') format('truetype'); - font-weight: normal; - font-style: normal; -} - -@font-face { - font-family: 'Shangu'; - src: url('fonts/shangu.woff') format('woff'), - url('fonts/shangu.ttf') format('truetype'); - font-weight: normal; - font-style: normal; -} - -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; - background-color: #f5f5f5; - color: #333; - line-height: 1.6; - padding: 20px; -} - -.container { - max-width: 900px; - margin: 0 auto; - background-color: white; - border-radius: 8px; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); - padding: 40px; -} - -.lang-switcher { - display: flex; - gap: 10px; - justify-content: flex-end; - margin-bottom: 20px; -} - -.lang-btn { - padding: 8px 20px; - border: 2px solid #007bff; - background-color: white; - color: #007bff; - border-radius: 6px; - cursor: pointer; - font-size: 14px; - font-weight: 500; - transition: all 0.3s ease; -} - -.lang-btn:hover { - background-color: #f0f8ff; -} - -.lang-btn.active { - background-color: #007bff; - color: white; -} - -.lang-btn:focus { - outline: none; - box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25); -} - -.loading { - text-align: center; - font-size: 18px; - color: #666; - padding: 40px; -} - -.error { - background-color: #fee; - border: 1px solid #fcc; - color: #c33; - padding: 20px; - border-radius: 4px; - margin-bottom: 20px; -} - -.petition-header { - border-bottom: 2px solid #007bff; - padding-bottom: 20px; - margin-bottom: 30px; -} - -.petition-header h1 { - font-size: 32px; - color: #222; - margin-bottom: 10px; -} - -.petition-header h2 { - font-size: 24px; - color: #555; - margin-bottom: 15px; -} - -.petition-header h2.dhivehi { - font-family: 'Shangu', 'Faruma', 'MV Faseyha', 'Waheed', 'Noto Sans Thaana', sans-serif; -} - -.dhivehi { - font-family: 'Utheem', 'Faruma', 'MV Faseyha', 'Waheed', 'Noto Sans Thaana', sans-serif; - direction: rtl; - text-align: right; -} - -.metadata { - display: flex; - gap: 20px; - flex-wrap: wrap; - margin-top: 15px; - font-size: 14px; - color: #666; -} - -.metadata span { - background-color: #f0f0f0; - padding: 6px 12px; - border-radius: 4px; -} - -.metadata span span { - background-color: transparent; - padding: 0; - font-weight: bold; - color: #333; -} - -.author-details { - background-color: #f9f9f9; - padding: 20px; - border-radius: 6px; - margin-bottom: 30px; -} - -.author-details h3 { - font-size: 18px; - color: #007bff; - margin-bottom: 12px; -} - -.author-details p { - margin-bottom: 8px; -} - -.petition-body { - margin-top: 30px; -} - -.petition-body h3 { - font-size: 20px; - color: #007bff; - margin-top: 30px; - margin-bottom: 15px; - padding-bottom: 10px; - border-bottom: 1px solid #e0e0e0; -} - -.body-content { - padding: 15px; - background-color: #fafafa; - border-radius: 4px; - line-height: 1.8; - white-space: pre-wrap; -} - -.body-content strong { - color: #222; -} - -.signature-count { - font-weight: bold; -} - -.signature-count span { - color: #007bff !important; -} - -.signature-section { - margin-top: 40px; - padding-top: 30px; - border-top: 2px solid #e0e0e0; -} - -.signature-section h3 { - font-size: 24px; - color: #007bff; - margin-bottom: 25px; -} - -.form-group { - margin-bottom: 20px; -} - -.form-group label { - display: block; - font-weight: 600; - margin-bottom: 8px; - color: #333; -} - -.form-group input[type="text"] { - width: 100%; - padding: 12px; - border: 2px solid #ddd; - border-radius: 6px; - font-size: 16px; - transition: border-color 0.3s ease; -} - -.form-group input[type="text"]:focus { - outline: none; - border-color: #007bff; -} - -/* ID card input: prefix + numeric field */ -.idcard-input { - display: flex; - align-items: center; - gap: 0; - max-width: 260px; - border: 1px solid #ddd; - border-radius: 6px; - overflow: hidden; - background: #fff; - transition: box-shadow 0.15s ease, border-color 0.15s ease; -} - -.idcard-prefix { - padding: 10px 12px; - font-weight: 700; - display: inline-flex; - align-items: center; - justify-content: center; - color: #333; - background: transparent; - border: none; /* prefix no longer has its own border */ - cursor: text; -} - -.idcard-input input[type="tel"] { - padding: 10px; - width: 120px; - font-size: 16px; - text-align: left; - border: none; /* input no longer has its own border */ - outline: none; - background: transparent; -} - -/* RTL adjustments: reverse order but keep the wrapper border intact */ -:dir(rtl) .idcard-input { - flex-direction: row-reverse; -} - -:dir(rtl) .idcard-input input[type="tel"] { - text-align: left; /* keep digits LTR within RTL page */ -} - -/* Highlight wrapper on focus */ -.idcard-input:focus-within { - border-color: #007bff; - box-shadow: 0 0 0 4px rgba(0, 123, 255, 0.08); -} - -.signature-pad-container { - border: 2px solid #ddd; - border-radius: 6px; - background-color: white; - display: block; - cursor: crosshair; - margin-bottom: 10px; -} - -#signature-pad { - display: block; - touch-action: none; - width: 100%; - max-width: 100%; - height: auto; - aspect-ratio: 3; -} - -.signature-actions { - margin-bottom: 15px; -} - -.form-buttons { - display: flex; - gap: 12px; - align-items: center; -} - -.btn-primary, -.btn-secondary { - padding: 12px 24px; - border: none; - border-radius: 6px; - font-size: 16px; - font-weight: 600; - cursor: pointer; - transition: all 0.3s ease; -} - -.btn-primary { - background-color: #007bff; - color: white; -} - -.btn-primary:hover { - background-color: #0056b3; -} - -.btn-secondary { - background-color: #6c757d; - color: white; -} - -.btn-secondary:hover { - background-color: #545b62; -} - -.form-message { - padding: 12px; - border-radius: 6px; - margin-bottom: 15px; - display: none; -} - -.form-message.success { - background-color: #d4edda; - border: 1px solid #c3e6cb; - color: #155724; -} - -.form-message.error { - background-color: #f8d7da; - border: 1px solid #f5c6cb; - color: #721c24; -} - -@media (max-width: 768px) { - .container { - padding: 20px; - } - - .petition-header h1 { - font-size: 24px; - } - - .petition-header h2 { - font-size: 18px; - } - - .metadata { - flex-direction: column; - gap: 10px; - } - - .form-buttons { - flex-direction: column; - width: 100%; - } - - .form-buttons button { - width: 100%; - } -} - -/* Tweet Modal Styles */ -.modal { - display: none; - position: fixed; - z-index: 1000; - left: 0; - top: 0; - width: 100%; - height: 100%; - background-color: rgba(0, 0, 0, 0.5); - animation: fadeIn 0.3s ease; -} - -.modal.show { - display: flex; - justify-content: center; - align-items: center; -} - -.modal-content { - background-color: white; - padding: 40px; - border-radius: 12px; - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); - max-width: 500px; - width: 90%; - position: relative; - animation: slideIn 0.3s ease; -} - -.close-modal { - position: absolute; - top: 15px; - right: 20px; - font-size: 28px; - font-weight: bold; - color: #999; - cursor: pointer; - transition: color 0.3s ease; -} - -.close-modal:hover { - color: #333; -} - -.modal-content h2 { - font-size: 24px; - color: #222; - margin-bottom: 15px; -} - -.modal-content p { - font-size: 16px; - color: #666; - margin-bottom: 25px; - line-height: 1.6; -} - -.modal-buttons { - display: flex; - flex-direction: column; - gap: 12px; - align-items: center; - width: 100%; -} - -.modal-buttons button { - width: 100%; - max-width: 300px; - justify-content: center; -} - -.modal-buttons .btn-primary { - background-color: #1DA1F2; - display: flex; - align-items: center; - gap: 8px; -} - -.modal-buttons .btn-primary:hover { - background-color: #1a91da; -} - -.modal-buttons .btn-primary i { - font-size: 18px; -} - -@keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -@keyframes slideIn { - from { - transform: translateY(-50px); - opacity: 0; - } - to { - transform: translateY(0); - opacity: 1; - } -} - -@media (max-width: 768px) { - .modal-content { - padding: 30px 20px; - max-width: 90%; - } - - .modal-content h2 { - font-size: 20px; - } -} diff --git a/frontend-react/package-lock.json b/frontend-react/package-lock.json index 2ead694..35222a4 100644 --- a/frontend-react/package-lock.json +++ b/frontend-react/package-lock.json @@ -20,6 +20,7 @@ "marked": "^17.0.1", "react": "^19.2.0", "react-dom": "^19.2.0", + "react-router-dom": "^7.13.0", "react-signature-canvas": "^1.1.0-alpha.2", "tailwind-merge": "^3.4.0" }, @@ -2804,6 +2805,18 @@ "dev": true, "license": "MIT" }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -4163,6 +4176,42 @@ } } }, + "node_modules/react-router": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.0.tgz", + "integrity": "sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw==", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.0.tgz", + "integrity": "sha512-5CO/l5Yahi2SKC6rGZ+HDEjpjkGaG/ncEP7eWFTvFxbHP8yeeI0PxTDjimtpXYlR3b3i9/WIL4VJttPrESIf2g==", + "dependencies": { + "react-router": "7.13.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, "node_modules/react-signature-canvas": { "version": "1.1.0-alpha.2", "resolved": "https://registry.npmjs.org/react-signature-canvas/-/react-signature-canvas-1.1.0-alpha.2.tgz", @@ -4286,6 +4335,11 @@ "semver": "bin/semver.js" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", diff --git a/frontend-react/package.json b/frontend-react/package.json index 2b8b4bf..3881eda 100644 --- a/frontend-react/package.json +++ b/frontend-react/package.json @@ -23,6 +23,7 @@ "marked": "^17.0.1", "react": "^19.2.0", "react-dom": "^19.2.0", + "react-router-dom": "^7.13.0", "react-signature-canvas": "^1.1.0-alpha.2", "tailwind-merge": "^3.4.0" }, diff --git a/frontend-react/src/App.tsx b/frontend-react/src/App.tsx index 99ec712..335d2b3 100644 --- a/frontend-react/src/App.tsx +++ b/frontend-react/src/App.tsx @@ -1,127 +1,17 @@ -import { useState, useRef } from "react"; -import { usePetition } from "@/hooks/usePetition"; -import { useLanguage } from "@/hooks/useLanguage"; -import { submitSignature } from "@/lib/api"; -import { LanguageSwitcher } from "@/components/layout/LanguageSwitcher"; -import { LoadingState } from "@/components/layout/LoadingState"; -import { ErrorState } from "@/components/layout/ErrorState"; -import { PetitionHeader } from "@/components/petition/PetitionHeader"; -import { AuthorCard } from "@/components/petition/AuthorCard"; -import { PetitionBody } from "@/components/petition/PetitionBody"; -import { SignatureForm } from "@/components/signature/SignatureForm"; -import { TweetModal } from "@/components/TweetModal"; -import { PenLine } from "lucide-react"; - -function getPetitionIdFromUrl(): string | null { - const urlParams = new URLSearchParams(window.location.search); - const id = urlParams.get("id"); - - return id; -} +import { BrowserRouter, Routes, Route } from "react-router-dom"; +import { HomePage } from "@/pages/HomePage"; +import { PetitionPage } from "@/pages/PetitionPage"; +import { CreatePetitionPage } from "@/pages/CreatePetitionPage"; function App() { - const petitionId = getPetitionIdFromUrl(); - const { petition, loading, error, refetch } = usePetition(petitionId); - const { language, setLanguage } = useLanguage(); - const [showTweetModal, setShowTweetModal] = useState(false); - const signatureFormRef = useRef(null); - - const scrollToSignForm = () => { - signatureFormRef.current?.scrollIntoView({ behavior: "smooth", block: "start" }); - }; - - const handleSubmit = async (data: { - name: string; - idCard: string; - signature: string; - turnstileToken: string; - }) => { - if (!petitionId) throw new Error("No petition ID"); - - await submitSignature(petitionId, data); - - // Show tweet modal after successful submission - setShowTweetModal(true); - - // Refresh petition data to update signature count - setTimeout(() => { - refetch(); - }, 1000); - }; - - // No petition ID in URL - if (!petitionId) { - return ( -
-
- -
-
- Powered by Mv Devs Union -
-
- ); - } - return ( -
-
- {loading ? ( -
- -
- ) : ( - <> - {error && } - - {petition && ( -
- - - - - - - - - - -
- -
- - setShowTweetModal(false)} - petition={petition} - language={language} - /> -
- )} - - )} -
- -
- Powered by Mv Devs Union -
-
+ + + } /> + } /> + } /> + + ); } diff --git a/frontend-react/src/hooks/usePetition.ts b/frontend-react/src/hooks/usePetition.ts index 842eb3a..cd42dab 100644 --- a/frontend-react/src/hooks/usePetition.ts +++ b/frontend-react/src/hooks/usePetition.ts @@ -1,6 +1,6 @@ import { useState, useEffect, useCallback } from "react"; import type { PetitionDetails } from "@/types/petition"; -import { fetchPetition, getDummyPetition } from "@/lib/api"; +import { fetchPetitionBySlug, getDummyPetition } from "@/lib/api"; interface UsePetitionResult { petition: PetitionDetails | null; @@ -9,15 +9,15 @@ interface UsePetitionResult { refetch: () => void; } -export function usePetition(petitionId: string | null): UsePetitionResult { +export function usePetition(slug: string | null): UsePetitionResult { const [petition, setPetition] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const loadPetition = useCallback(async () => { - if (!petitionId) { + if (!slug) { setLoading(false); - setError("No petition ID provided"); + setError("No petition slug provided"); return; } @@ -25,7 +25,7 @@ export function usePetition(petitionId: string | null): UsePetitionResult { setError(null); try { - const data = await fetchPetition(petitionId); + const data = await fetchPetitionBySlug(slug); setPetition(data); } catch (err) { console.warn( @@ -36,11 +36,11 @@ export function usePetition(petitionId: string | null): UsePetitionResult { setError( "Failed to load petition from server — showing dummy data for development.", ); - setPetition(getDummyPetition(petitionId)); + setPetition(getDummyPetition(slug)); } finally { setLoading(false); } - }, [petitionId]); + }, [slug]); useEffect(() => { loadPetition(); diff --git a/frontend-react/src/lib/api.ts b/frontend-react/src/lib/api.ts index ec6e2d5..2d206c5 100644 --- a/frontend-react/src/lib/api.ts +++ b/frontend-react/src/lib/api.ts @@ -17,6 +17,69 @@ export async function fetchPetition( return response.json(); } +export async function fetchPetitionBySlug( + slug: string, +): Promise { + const response = await fetch( + `${API_BASE_URL}/api/Sign/petition/by-slug/${slug}`, + ); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + return response.json(); +} + +export interface PetitionFormData { + slug: string; + nameDhiv: string; + nameEng: string; + startDate: string; // dd-MM-yyyy + authorName: string; + authorNid: string; + petitionBodyDhiv: string; + petitionBodyEng: string; +} + +export interface SubmitPetitionResponse { + message: string; + petitionId: string; + slug: string; + fileName: string; + filePath: string; + authorId: string; +} + +export async function submitPetition( + data: PetitionFormData, +): Promise { + const formData = new FormData(); + formData.append("Slug", data.slug); + formData.append("NameDhiv", data.nameDhiv); + formData.append("NameEng", data.nameEng); + formData.append("StartDate", data.startDate); + formData.append("AuthorName", data.authorName); + formData.append("AuthorNid", data.authorNid); + formData.append("PetitionBodyDhiv", data.petitionBodyDhiv); + formData.append("PetitionBodyEng", data.petitionBodyEng); + + const response = await fetch( + `${API_BASE_URL}/api/Debug/upload-petition-form`, + { + method: "POST", + body: formData, + }, + ); + + if (!response.ok) { + const errorData = await response.json().catch(() => ({})); + throw new Error(errorData.message || `HTTP error! status: ${response.status}`); + } + + return response.json(); +} + export async function submitSignature( petitionId: string, submission: SignatureSubmission, @@ -39,9 +102,10 @@ export async function submitSignature( } // Dummy petition for development when API is not available -export function getDummyPetition(petitionId: string): PetitionDetails { +export function getDummyPetition(slug: string): PetitionDetails { return { - id: petitionId || "dev-petition", + id: "dev-petition-id", + slug: slug || "demo-petition", nameEng: "Demo Petition: Improve Local Services", nameDhiv: "Demo Petition", startDate: new Date().toLocaleDateString(), diff --git a/frontend-react/src/pages/CreatePetitionPage.tsx b/frontend-react/src/pages/CreatePetitionPage.tsx new file mode 100644 index 0000000..a762f76 --- /dev/null +++ b/frontend-react/src/pages/CreatePetitionPage.tsx @@ -0,0 +1,400 @@ +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { submitPetition, type PetitionFormData } from "@/lib/api"; +import { + FileText, + Send, + AlertCircle, + CheckCircle, + AlertTriangle, + ExternalLink, +} from "lucide-react"; + +function GuidelinesModal({ onAccept }: { onAccept: () => void }) { + return ( +
+
+
+
+
+ +
+

+ Before You Create a Petition +

+
+ +
+

+ Please familiarize yourself with the laws and regulations for + drafting a petition: +

+ + + + majlis.gov.mv/en/pes/petitions + + +
+

+ If you skip this step, there is a 100% chance we will reject + hosting your petition. +

+
+ +
+

Important Rules (TLDR):

+
    +
  • + 1. + + You cannot mention people or businesses + directly in your petition. + +
  • +
  • + 2. + + You cannot petition for something that only + benefits yourself. + +
  • +
  • + 3. + + No anonymous petitions. Your Name and NID + will appear publicly on the petition. The submitter's + identity is always visible. + +
  • +
+
+
+ +
+ + + Read Full Guidelines First + +
+
+
+
+ ); +} + +export function CreatePetitionPage() { + const navigate = useNavigate(); + const [showGuidelines, setShowGuidelines] = useState(true); + const [isSubmitting, setIsSubmitting] = useState(false); + const [error, setError] = useState(null); + const [success, setSuccess] = useState<{ slug: string } | null>(null); + + const [formData, setFormData] = useState({ + slug: "", + nameDhiv: "", + nameEng: "", + startDate: formatDateForInput(new Date()), + authorName: "", + authorNid: "", + petitionBodyDhiv: "", + petitionBodyEng: "", + }); + + function formatDateForInput(date: Date): string { + const day = String(date.getDate()).padStart(2, "0"); + const month = String(date.getMonth() + 1).padStart(2, "0"); + const year = date.getFullYear(); + return `${day}-${month}-${year}`; + } + + const handleChange = ( + e: React.ChangeEvent + ) => { + const { name, value } = e.target; + setFormData((prev) => ({ ...prev, [name]: value })); + }; + + const generateSlug = () => { + const slug = formData.nameEng + .toLowerCase() + .replace(/[^a-z0-9\s-]/g, "") + .replace(/\s+/g, "-") + .replace(/-+/g, "-") + .trim(); + setFormData((prev) => ({ ...prev, slug })); + }; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setIsSubmitting(true); + setError(null); + + try { + const result = await submitPetition(formData); + setSuccess({ slug: result.slug }); + } catch (err) { + setError(err instanceof Error ? err.message : "Failed to submit petition"); + } finally { + setIsSubmitting(false); + } + }; + + if (success) { + return ( +
+
+
+
+
+ +
+
+

+ Petition Created Successfully! +

+

+ Your petition has been submitted and is now live. +

+
+ + +
+
+
+
+ ); + } + + return ( +
+ {showGuidelines && ( + setShowGuidelines(false)} /> + )} + +
+
+
+ +
+

+ Create a New Petition +

+
+ + {error && ( +
+ +

{error}

+
+ )} + +
+ {/* Petition Names */} +
+
+ + !formData.slug && generateSlug()} + required + className="w-full px-4 py-3 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors" + placeholder="Enter petition title in English" + /> +
+
+ + +
+
+ + {/* Slug */} +
+ +
+ + +
+

+ URL: /Petition/{formData.slug || "your-slug"} +

+
+ + {/* Start Date */} +
+ + +
+ + {/* Author Info */} +
+
+ + +
+
+ + +
+
+ + {/* Petition Bodies */} +
+ +