mirror of
https://github.com/MvDevsUnion/WPetition.git
synced 2026-01-26 15:29:28 +00:00
big updates
added read more added a prompt to skip reading and auto scroll to sign moved the erase button to the sig pad so easier to access updated icon on submit button
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { useState, useRef } from "react";
|
||||
import { usePetition } from "@/hooks/usePetition";
|
||||
import { useLanguage } from "@/hooks/useLanguage";
|
||||
import { submitSignature } from "@/lib/api";
|
||||
@@ -10,6 +10,7 @@ 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);
|
||||
@@ -23,6 +24,11 @@ function App() {
|
||||
const { petition, loading, error, refetch } = usePetition(petitionId);
|
||||
const { language, setLanguage } = useLanguage();
|
||||
const [showTweetModal, setShowTweetModal] = useState(false);
|
||||
const signatureFormRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const scrollToSignForm = () => {
|
||||
signatureFormRef.current?.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
};
|
||||
|
||||
const handleSubmit = async (data: {
|
||||
name: string;
|
||||
@@ -77,6 +83,14 @@ function App() {
|
||||
|
||||
<PetitionHeader petition={petition} language={language} />
|
||||
|
||||
<button
|
||||
onClick={scrollToSignForm}
|
||||
className={`w-full flex items-center justify-center gap-2 bg-blue-600 hover:bg-blue-700 text-white font-medium py-3 px-6 rounded-lg transition-colors ${language === "dv" ? "flex-row-reverse dhivehi" : ""}`}
|
||||
>
|
||||
<PenLine className="w-5 h-5" />
|
||||
{language === "dv" ? "މިހާރު ސޮއި ކުރައްވާ" : "Sign Now"}
|
||||
</button>
|
||||
|
||||
<AuthorCard
|
||||
author={petition.authorDetails}
|
||||
language={language}
|
||||
@@ -88,7 +102,9 @@ function App() {
|
||||
language={language}
|
||||
/>
|
||||
|
||||
<SignatureForm language={language} onSubmit={handleSubmit} />
|
||||
<div ref={signatureFormRef}>
|
||||
<SignatureForm language={language} onSubmit={handleSubmit} />
|
||||
</div>
|
||||
|
||||
<TweetModal
|
||||
open={showTweetModal}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useMemo } from "react";
|
||||
import { useMemo, useState } from "react";
|
||||
import { marked } from "marked";
|
||||
import DOMPurify from "dompurify";
|
||||
import { ChevronDown, ChevronUp } from "lucide-react";
|
||||
import type { Language } from "@/types/petition";
|
||||
|
||||
interface PetitionBodyProps {
|
||||
@@ -9,11 +10,14 @@ interface PetitionBodyProps {
|
||||
language: Language;
|
||||
}
|
||||
|
||||
const COLLAPSED_HEIGHT = 300;
|
||||
|
||||
export function PetitionBody({
|
||||
bodyEng,
|
||||
bodyDhiv,
|
||||
language,
|
||||
}: PetitionBodyProps) {
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
const content = language === "dv" ? bodyDhiv : bodyEng;
|
||||
const isRtl = language === "dv";
|
||||
|
||||
@@ -24,21 +28,46 @@ export function PetitionBody({
|
||||
|
||||
return (
|
||||
<div className="mt-8">
|
||||
<div
|
||||
className={`leading-loose prose prose-slate max-w-none text-slate-800 md:prose-lg
|
||||
prose-p:mb-6 prose-p:mt-0
|
||||
prose-headings:text-slate-900 prose-headings:font-bold prose-headings:mb-6 prose-headings:mt-12
|
||||
|
||||
[&_hr]:my-8! [&_hr]:border-slate-300!
|
||||
|
||||
[&_ul]:list-disc! [&_ul]:my-6!
|
||||
[&_ol]:list-decimal! [&_ol]:my-6!
|
||||
[&_li]:my-2!
|
||||
[&_li::before]:content-none!
|
||||
|
||||
${isRtl ? "dhivehi dir-rtl text-right [&_ul]:pr-12! [&_ol]:pr-12!" : "text-left [&_ul]:pl-12! [&_ol]:pl-12!"}`}
|
||||
dangerouslySetInnerHTML={{ __html: htmlContent }}
|
||||
/>
|
||||
<div className="relative">
|
||||
<div
|
||||
className={`leading-loose prose prose-slate max-w-none text-slate-800 md:prose-lg
|
||||
prose-p:mb-6 prose-p:mt-0
|
||||
prose-headings:text-slate-900 prose-headings:font-bold prose-headings:mb-6 prose-headings:mt-12
|
||||
|
||||
[&_hr]:my-8! [&_hr]:border-slate-300!
|
||||
|
||||
[&_ul]:list-disc! [&_ul]:my-6!
|
||||
[&_ol]:list-decimal! [&_ol]:my-6!
|
||||
[&_li]:my-2!
|
||||
[&_li::before]:content-none!
|
||||
|
||||
${isRtl ? "dhivehi dir-rtl text-right [&_ul]:pr-12! [&_ol]:pr-12!" : "text-left [&_ul]:pl-12! [&_ol]:pl-12!"}
|
||||
${!isExpanded ? "overflow-hidden" : ""}`}
|
||||
style={!isExpanded ? { maxHeight: `${COLLAPSED_HEIGHT}px` } : undefined}
|
||||
dangerouslySetInnerHTML={{ __html: htmlContent }}
|
||||
/>
|
||||
|
||||
{!isExpanded && (
|
||||
<div className="absolute bottom-0 left-0 right-0 h-24 bg-gradient-to-t from-white to-transparent pointer-events-none" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => setIsExpanded(!isExpanded)}
|
||||
className={`mt-4 flex items-center gap-2 text-blue-600 hover:text-blue-700 font-medium transition-colors ${isRtl ? "flex-row-reverse" : ""}`}
|
||||
>
|
||||
{isExpanded ? (
|
||||
<>
|
||||
<ChevronUp className="w-5 h-5" />
|
||||
{language === "dv" ? "ކުޑަކޮށް ދައްކާ" : "Show Less"}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<ChevronDown className="w-5 h-5" />
|
||||
{language === "dv" ? "އިތުރަށް ކިޔާ" : "Read More"}
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||
import { SignaturePad, type SignaturePadRef } from "./SignaturePad";
|
||||
import { Turnstile } from "@marsidev/react-turnstile";
|
||||
import { Eraser, Send, CheckCircle, AlertCircle } from "lucide-react";
|
||||
import { Eraser, Check, CheckCircle, AlertCircle } from "lucide-react";
|
||||
import type { Language } from "@/types/petition";
|
||||
|
||||
interface SignatureFormProps {
|
||||
@@ -200,8 +200,18 @@ export function SignatureForm({ language, onSubmit }: SignatureFormProps) {
|
||||
<Label className={`text-slate-700 ${isRtl ? "dhivehi" : ""}`}>
|
||||
{language === "en" ? "Signature" : "ސޮއި"}
|
||||
</Label>
|
||||
<div className="border border-input rounded-lg overflow-hidden shadow-sm hover:border-ring/50 transition-colors">
|
||||
<div className="relative border border-input rounded-lg overflow-hidden shadow-sm hover:border-ring/50 transition-colors">
|
||||
<SignaturePad ref={signaturePadRef} />
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
onClick={handleClear}
|
||||
size="icon"
|
||||
className="absolute top-2 right-2 h-8 w-8 text-red-500 hover:text-red-700 hover:bg-red-50/80 bg-white/70 backdrop-blur-sm"
|
||||
title={language === "en" ? "Clear Signature" : "ފޮހެލާ"}
|
||||
>
|
||||
<Eraser className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<p className={`text-xs text-slate-500 ${isRtl ? "dhivehi" : ""}`}>
|
||||
{language === "en"
|
||||
@@ -243,38 +253,25 @@ export function SignatureForm({ language, onSubmit }: SignatureFormProps) {
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{/* Turnstile */}
|
||||
<div className="flex justify-center sm:justify-start">
|
||||
{/* Turnstile and Submit */}
|
||||
<div className="flex flex-col items-center sm:items-start gap-4">
|
||||
<Turnstile
|
||||
siteKey="0x4AAAAAACHH4QC3wIhkCuhd"
|
||||
onSuccess={setTurnstileToken}
|
||||
onError={() => setTurnstileToken(null)}
|
||||
onExpire={() => setTurnstileToken(null)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Form Buttons */}
|
||||
<div className={`flex gap-4 pt-4 ${isRtl ? "flex-row-reverse" : ""}`}>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
onClick={handleClear}
|
||||
className={`text-slate-500 hover:text-slate-900 ${isRtl ? "dhivehi" : ""}`}
|
||||
>
|
||||
<Eraser className="h-4 w-4 mr-2" />
|
||||
{language === "en" ? "Clear Signature" : "ފޮހެލާ"}
|
||||
</Button>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
size="lg"
|
||||
className={`min-w-[140px] shadow-md hover:shadow-lg transition-all ${isRtl ? "dhivehi" : ""}`}
|
||||
className={`w-[300px] bg-green-600 hover:bg-green-700 shadow-md hover:shadow-lg transition-all ${isRtl ? "dhivehi" : ""}`}
|
||||
>
|
||||
{isSubmitting ? (
|
||||
<span className="animate-pulse">Submitting...</span>
|
||||
) : (
|
||||
<>
|
||||
<Send className="h-4 w-4 mr-2" />
|
||||
<Check className="h-5 w-5 mr-2" />
|
||||
{language === "en" ? "Submit Petition" : "ހުށަހެޅުއް"}
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -60,8 +60,7 @@ export const SignaturePad = forwardRef<SignaturePadRef, SignaturePadProps>(
|
||||
ref={sigCanvasRef}
|
||||
penColor="black"
|
||||
canvasProps={{
|
||||
className: "w-full",
|
||||
style: { aspectRatio: "3", height: "auto" },
|
||||
className: "w-full aspect-[2/1] md:aspect-[3/1]",
|
||||
}}
|
||||
onBegin={onBegin}
|
||||
onEnd={onEnd}
|
||||
|
||||
Reference in New Issue
Block a user