Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions frontend/public/dashboard/star-q.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 37 additions & 0 deletions frontend/src/app/creator/quests/new/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"use client";

import { useRouter } from "next/navigation";
import { useState } from "react";
import QuestsHub from "@/components/creator/quests/QuestsHub";
import QuestWizard from "@/components/creator/quests/wizard/QuestWizard";
import PublishSuccess from "@/components/creator/quests/wizard/PublishSuccess";

export default function CreateQuestPage() {
const router = useRouter();
const [publishedQuestId, setPublishedQuestId] = useState<string | null>(null);

if (publishedQuestId) {
return <PublishSuccess questId={publishedQuestId} />;
}

return (
<>
<div className="h-[calc(100vh-5rem)] overflow-y-auto px-5 py-4 sm:px-8 sm:py-6 lg:px-12">
<QuestsHub />
</div>

<div className="fixed inset-0 z-50">
<button
type="button"
aria-label="Close quest creator"
onClick={() => router.push("/creator/quests")}
className="absolute inset-0 bg-black/60 backdrop-blur-[1px]"
/>

<div className="absolute inset-y-0 right-0 w-full border-l border-white/10 bg-[#0B0913] shadow-2xl sm:w-[45%]">
<QuestWizard onPublish={setPublishedQuestId} />
</div>
</div>
</>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default function EmptyActiveQuests() {
</p>
<Link
href="/creator/quests/new"
className="mt-2 rounded-lg bg-[#9011FF] px-5 py-2.5 text-sm font-semibold text-white transition-colors hover:bg-[#7c0de0]"
className="mt-2 rounded-lg bg-[#8B5CF6] px-5 py-2.5 text-sm font-semibold text-white transition-colors hover:bg-[#7c0de0]"
>
+ Add new Quest
</Link>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/creator/quests/QuestRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import QuestRowMenu from "./QuestRowMenu";
import type { QuestRowData } from "./types";

const TAG_STYLES: Record<QuestRowData["tagVariant"], string> = {
active: "bg-[#9011FF]/20 text-[#B78CFF]",
active: "bg-[#8B5CF6]/20 text-[#B78CFF]",
draft: "bg-white/10 text-white/60",
completed: "bg-emerald-500/15 text-emerald-400",
};
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/creator/quests/QuestsHub.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export default function QuestsHub() {
</div>
<Link
href="/creator/quests/new"
className="inline-flex shrink-0 items-center justify-center rounded-lg bg-[#9011FF] px-4 py-2.5 text-sm font-semibold text-white transition-colors hover:bg-[#7c0de0]"
className="inline-flex shrink-0 items-center justify-center rounded-lg bg-[#8B5CF6] px-4 py-2.5 text-sm font-semibold text-white transition-colors hover:bg-[#7c0de0]"
>
+ Add new Quest
</Link>
Expand Down Expand Up @@ -115,14 +115,14 @@ export default function QuestsHub() {
<span
className={`rounded-full px-1.5 py-0.5 text-xs ${
isActive
? "bg-[#9011FF]/20 text-[#B78CFF]"
? "bg-[#8B5CF6]/20 text-[#B78CFF]"
: "bg-white/5 text-white/40"
}`}
>
{counts[tab.key]}
</span>
{isActive ? (
<span className="absolute inset-x-0 bottom-[-1px] h-0.5 bg-[#9011FF]" />
<span className="absolute inset-x-0 bottom-[-1px] h-0.5 bg-[#8B5CF6]" />
) : null}
</button>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
"use client";

import { useEffect } from "react";
import Image from "next/image";
import { X } from "lucide-react";
import { formatDateTime, rewardCalculations, type QuestWizardData } from "./types";

export default function ParticipantPreviewModal({
data,
onClose,
}: {
data: QuestWizardData;
onClose: () => void;
}) {
const { rewardPerWinner } = rewardCalculations(data.rewards);

useEffect(() => {
function handleKeyDown(event: KeyboardEvent) {
if (event.key === "Escape") onClose();
}
document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
}, [onClose]);

return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 px-4">
<div className="w-full max-w-xl rounded-2xl border border-white/10 bg-[#0D0B10] p-6 shadow-2xl">
<div className="mb-5 flex items-center justify-between">
<h2 className="text-sm font-semibold text-white">
Participant preview
</h2>
<button
type="button"
onClick={onClose}
aria-label="Close preview"
className="flex size-8 items-center justify-center rounded-md text-white/50 transition-colors hover:bg-white/5 hover:text-white"
>
<X className="size-4" />
</button>
</div>

<h3 className="text-xl font-semibold text-white">
{data.basics.title || "Untitled quest"}
</h3>
<div className="mt-2 flex items-center gap-2 text-sm text-white/50">
<Image
src="/namelogo.png"
alt=""
width={16}
height={16}
className="size-4 rounded object-cover"
/>
Ruze.Stellar
</div>

<p className="mt-4 text-sm leading-relaxed text-white/70">
{data.basics.description || "No description provided yet."}
</p>

<div className="mt-5 grid grid-cols-3 gap-4 border-y border-white/10 py-4">
<div>
<p className="text-xs text-white/40">Reward</p>
<p className="mt-1 text-sm font-medium text-white">
{rewardPerWinner.toLocaleString(undefined, {
maximumFractionDigits: 2,
})}{" "}
XLM
</p>
</div>
<div>
<p className="text-xs text-white/40">Time</p>
<p className="mt-1 text-sm font-medium text-white">
{data.basics.completionDuration}
</p>
</div>
<div>
<p className="text-xs text-white/40">Closes</p>
<p className="mt-1 text-sm font-medium text-white">
{formatDateTime(data.schedule.closingDateTime)}
</p>
</div>
</div>

<div className="mt-5">
<p className="mb-3 text-sm font-semibold text-white">
What you&apos;ll do
</p>
<ol className="flex flex-col gap-3">
{data.tasks.map((task, index) => (
<li key={task.id} className="flex gap-3">
<span className="flex size-5 shrink-0 items-center justify-center rounded-full bg-[#8B5CF6]/20 text-xs font-semibold text-[#B78CFF]">
{index + 1}
</span>
<div className="min-w-0">
<p className="text-sm text-white">
{task.title || "Untitled task"}
</p>
{task.instruction ? (
<p className="text-xs text-white/45">{task.instruction}</p>
) : null}
</div>
</li>
))}
</ol>
</div>
</div>
</div>
);
}
38 changes: 38 additions & 0 deletions frontend/src/components/creator/quests/wizard/PublishSuccess.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Image from "next/image";
import Link from "next/link";
import { ArrowRight } from "lucide-react";

export default function PublishSuccess({ questId }: { questId: string }) {
return (
<div className="flex h-full min-h-[calc(100vh-5rem)] flex-1 flex-col items-center justify-center gap-4 px-4 text-center">
<Image
src="/dashboard/star-q.svg"
alt=""
width={80}
height={80}
className="size-20"
/>
<h2 className="text-2xl font-semibold text-white">
Quest Published Successfully
</h2>
<p className="max-w-sm text-sm text-white/50">
Your quest has been successfully added to the campaign
</p>
<div className="mt-2 flex items-center gap-3">
<Link
href="/creator/quests"
className="rounded-lg border border-white/15 px-4 py-2.5 text-sm font-medium text-white transition-colors hover:bg-white/5"
>
Close
</Link>
<Link
href={`/creator/quests/${questId}`}
className="flex items-center gap-1.5 rounded-lg bg-[#8B5CF6] px-4 py-2.5 text-sm font-semibold text-white transition-colors hover:bg-[#7c0de0]"
>
View quest
<ArrowRight className="size-4" />
</Link>
</div>
</div>
);
}
Loading
Loading