Skip to content

Commit

Permalink
✨ Update admin layout and pages (#976)
Browse files Browse the repository at this point in the history
  • Loading branch information
lukevella authored Jan 13, 2024
1 parent 0ba7e9c commit a1bac0c
Show file tree
Hide file tree
Showing 81 changed files with 2,060 additions and 1,267 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"editor.codeActionsOnSave": {
"source.fixAll": true
"source.fixAll": "explicit"
},
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.preferences.importModuleSpecifier": "non-relative",
Expand Down
14 changes: 7 additions & 7 deletions apps/web/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,12 @@ const nextConfig = {
},
];
},
sentry: {
hideSourceMaps: false,
},
};

const sentryWebpackPluginOptions = {
// Additional config options for the Sentry Webpack plugin. Keep in mind that
org: "stack-snap",
project: "rallly",
// Additional config ocptions for the Sentry Webpack plugin. Keep in mind that
// the following options are set automatically, and overriding them is not
// recommended:
// release, url, org, project, authToken, configFile, stripPrefix,
Expand All @@ -70,8 +69,9 @@ const sentryWebpackPluginOptions = {
// https://github.com/getsentry/sentry-webpack-plugin#options.
};

const withBundleAnalyzerConfig = withBundleAnalyzer(nextConfig);
// Make sure adding Sentry options is the last code to run before exporting, to
// ensure that your source maps include changes from all other Webpack plugins
module.exports = withSentryConfig(
withBundleAnalyzer(nextConfig, sentryWebpackPluginOptions),
);
module.exports = process.env.SENTRY_AUTH_TOKEN
? withSentryConfig(withBundleAnalyzerConfig, sentryWebpackPluginOptions)
: withBundleAnalyzerConfig;
1 change: 1 addition & 0 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"iron-session": "^6.3.1",
"js-cookie": "^3.0.1",
"lodash": "^4.17.21",
"lucide-react": "^0.294.0",
"micro": "^10.0.1",
"nanoid": "^4.0.0",
"next-auth": "^4.24.5",
Expand Down
37 changes: 23 additions & 14 deletions apps/web/public/locales/en/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,6 @@
"dates": "Dates",
"menu": "Menu",
"useLocaleDefaults": "Use locale defaults",
"inviteParticipantsDescription": "Copy and share this invite link to start gathering responses from your participants.",
"inviteLink": "Invite Link",
"inviteParticipantLinkInfo": "Anyone with this link will be able to vote on your poll.",
"support": "Support",
"billing": "Billing",
"guestPollAlertDescription": "<0>Create an account</0> or <1>login</1> to claim this poll.",
Expand All @@ -135,7 +132,6 @@
"permissionDenied": "Unauthorized",
"permissionDeniedDescription": "If you are the poll creator, please login to access your poll",
"loginDifferent": "Switch user",
"share": "Share",
"timeShownIn": "Times shown in {timeZone}",
"editDetailsDescription": "Change the details of your event.",
"finalizeDescription": "Select a final date for your event.",
Expand Down Expand Up @@ -210,14 +206,7 @@
"earlyAccess": "Get early access to new features",
"earlyAdopterDescription": "As an early adopter, you'll lock in your subscription rate and won't be affected by future price increases.",
"upgradeNowSaveLater": "Upgrade now, save later",
"savePercent": "Save {percent}%",
"priceIncreaseSoon": "Price increase soon.",
"lockPrice": "Upgrade today to keep this price forever.",
"features": "Get access to all current and future Pro features!",
"noAds": "No ads",
"supportProject": "Support this project",
"pricing": "Pricing",
"pleaseUpgrade": "Please upgrade to Pro to use this feature",
"pollSettingsDescription": "Customize the behaviour of your poll",
"requireParticipantEmailLabel": "Make email address required for participants",
"hideParticipantsLabel": "Hide participant list from other participants",
Expand All @@ -226,8 +215,28 @@
"authErrorDescription": "There was an error logging you in. Please try again.",
"authErrorCta": "Go to login page",
"continueAs": "Continue as",
"finalizeFeature": "Finalize",
"duplicateFeature": "Duplicate",
"pageMovedDescription": "Redirecting to <a>{newUrl}</a>",
"notRegistered": "Don't have an account? <a>Register</a>"
"notRegistered": "Don't have an account? <a>Register</a>",
"comingSoon": "Coming Soon",
"integrations": "Integrations",
"contacts": "Contacts",
"unlockFeatures": "Unlock all Pro features.",
"back": "Back",
"pollStatusAll": "All",
"pollStatusLive": "Live",
"pollStatusFinalized": "Finalized",
"pending": "Pending",
"xMore": "{count} more",
"share": "Share",
"pageXOfY": "Page {currentPage} of {pageCount}",
"noParticipants": "No participants",
"userId": "User ID",
"aboutGuest": "Guest User",
"aboutGuestDescription": "Profile settings are not available for guest users. <0>Sign in</0> to your existing account or <1>create a new account</1> to customize your profile.",
"logoutDescription": "Sign out of your existing session",
"events": "Events",
"registrations": "Registrations",
"inviteParticipantsDescription": "Copy and share the invite link to start gathering responses from your participants.",
"inviteLink": "Invite Link",
"inviteParticipantLinkInfo": "Anyone with this link will be able to vote on your poll."
}
59 changes: 54 additions & 5 deletions apps/web/src/app/[locale]/(admin)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
"use client";
import { cn } from "@rallly/ui";
import { Button } from "@rallly/ui/button";
import { MenuIcon } from "lucide-react";
import Link from "next/link";
import { signIn, useSession } from "next-auth/react";
import React from "react";

import { StandardLayout } from "@/components/layouts/standard-layout";
import { Sidebar } from "@/app/[locale]/(admin)/sidebar";
import { LogoLink } from "@/app/components/logo-link";
import { CurrentUserAvatar } from "@/components/user";
import { isSelfHosted } from "@/utils/constants";

const Auth = ({ children }: { children: React.ReactNode }) => {
Expand All @@ -22,13 +27,57 @@ const Auth = ({ children }: { children: React.ReactNode }) => {
return null;
};

export default function Layout({ children }: { children: React.ReactNode }) {
function MobileNavigation() {
return (
<div className="lg:hidden shadow-sm bg-gray-100 border-b flex items-center justify-between px-4 py-3">
<LogoLink />
<div className="flex gap-x-2.5 justify-end">
<Link
href="/settings/profile"
className="inline-flex items-center w-7 h-9"
>
<CurrentUserAvatar size="sm" />
</Link>
<Button asChild variant="ghost">
<Link href="/menu">
<MenuIcon className="h-4 w-4 text-muted-foreground" />
</Link>
</Button>
</div>
</div>
);
}

export default async function Layout({
children,
}: {
children: React.ReactNode;
}) {
function SidebarLayout() {
return (
<div className="lg:flex h-full bg-gray-50">
<MobileNavigation />
<div
className={cn(
"hidden lg:flex lg:w-72 bg-gray-100 shrink-0 flex-col gap-y-5 overflow-y-auto border-r lg:px-6 lg:py-4 px-5 py-4",
)}
>
<div>
<LogoLink />
</div>
<Sidebar />
</div>
<div className={cn("grow overflow-auto bg-gray-50")}>{children}</div>
</div>
);
}

if (isSelfHosted) {
return (
<Auth>
<StandardLayout>{children}</StandardLayout>
<SidebarLayout />
</Auth>
);
}
return <StandardLayout>{children}</StandardLayout>;
return <SidebarLayout />;
}
42 changes: 42 additions & 0 deletions apps/web/src/app/[locale]/(admin)/menu-item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"use client";

import { cn } from "@rallly/ui";
import { Link } from "lucide-react";
import { usePathname } from "next/navigation";

import { IconComponent } from "@/types";

export function MenuItem({
href,
children,
icon: Icon,
}: {
href: string;
icon: IconComponent;
children: React.ReactNode;
}) {
const pathname = usePathname();
const isCurrent = pathname === href;
return (
<Link
href={href}
className={cn(
isCurrent
? "bg-gray-200 text-indigo-600"
: "text-gray-700 hover:text-primary",
"group flex items-center gap-x-3 rounded-md py-2 px-3 text-sm leading-6 font-semibold",
)}
>
<Icon
className={cn(
isCurrent
? "text-indigo-600"
: "text-gray-400 group-hover:text-indigo-600",
"h-5 w-5 shrink-0",
)}
aria-hidden="true"
/>
{children}
</Link>
);
}
3 changes: 3 additions & 0 deletions apps/web/src/app/[locale]/(admin)/new/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Loading() {
return null;
}
33 changes: 31 additions & 2 deletions apps/web/src/app/[locale]/(admin)/new/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,37 @@
import { Button } from "@rallly/ui/button";
import Link from "next/link";
import { Trans } from "react-i18next/TransWithoutContext";

import {
PageContainer,
PageContent,
PageHeader,
PageTitle,
} from "@/app/components/page-layout";
import { getTranslation } from "@/app/i18n";
import { CreatePoll } from "@/components/create-poll";

export default function Page() {
return <CreatePoll />;
export default async function Page({ params }: { params: { locale: string } }) {
const { t } = await getTranslation(params.locale);
return (
<PageContainer>
<PageHeader>
<div className="flex justify-between items-center gap-x-4">
<PageTitle>
<Trans t={t} i18nKey="polls" />
</PageTitle>
<Button asChild>
<Link href="/polls">
<Trans t={t} i18nKey="cancel" defaults="Cancel" />
</Link>
</Button>
</div>
</PageHeader>
<PageContent>
<CreatePoll />
</PageContent>
</PageContainer>
);
}

export async function generateMetadata({
Expand Down
41 changes: 38 additions & 3 deletions apps/web/src/app/[locale]/(admin)/polls/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,44 @@
import { Button } from "@rallly/ui/button";
import { PenBoxIcon } from "lucide-react";
import Link from "next/link";
import { Trans } from "react-i18next/TransWithoutContext";

import {
PageContainer,
PageContent,
PageHeader,
PageTitle,
} from "@/app/components/page-layout";
import { getTranslation } from "@/app/i18n";

import { PollsPage } from "./polls-page";
import { PollsList } from "./polls-list";

export default function Page() {
return <PollsPage />;
export default async function Page({ params }: { params: { locale: string } }) {
const { t } = await getTranslation(params.locale);
return (
<PageContainer>
<PageHeader>
<div className="flex justify-between items-center gap-x-4">
<PageTitle>
<Trans t={t} i18nKey="polls" />
</PageTitle>
<Button asChild>
<Link href="/new">
<PenBoxIcon className="w-4 text-muted-foreground h-4" />
<span className="hidden sm:inline">
<Trans t={t} i18nKey="newPoll" />
</span>
</Link>
</Button>
</div>
</PageHeader>
<PageContent>
<div className="space-y-6">
<PollsList />
</div>
</PageContent>
</PageContainer>
);
}

export async function generateMetadata({
Expand Down
55 changes: 55 additions & 0 deletions apps/web/src/app/[locale]/(admin)/polls/polls-folders.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"use client";

import { cn } from "@rallly/ui";
import { Button } from "@rallly/ui/button";
import Link from "next/link";
import { usePathname, useSearchParams } from "next/navigation";

import { Trans } from "@/components/trans";

function PollFolder({
href,
children,
}: {
href: string;
children: React.ReactNode;
}) {
const pathname = usePathname() ?? "";
const searchParams = useSearchParams();
const query = searchParams?.has("status")
? `?${searchParams?.toString()}`
: "";
const currentUrl = pathname + query;
const isActive = href === currentUrl;
return (
<Button
asChild
className={cn(
isActive
? "bg-gray-100"
: "shadow-sm text-muted-foreground hover:bg-gray-100 active:bg-gray-200",
)}
>
<Link href={href}>{children}</Link>
</Button>
);
}

export function PollFolders() {
return (
<div className="flex flex-wrap gap-3">
<PollFolder href="/polls">
<Trans i18nKey="pollStatusAll" defaults="All" />
</PollFolder>
<PollFolder href="/polls?status=live">
<Trans i18nKey="pollStatusLive" defaults="Live" />
</PollFolder>
<PollFolder href="/polls?status=paused">
<Trans i18nKey="pollStatusPaused" defaults="Paused" />
</PollFolder>
<PollFolder href="/polls?status=finalized">
<Trans i18nKey="pollStatusFinalized" defaults="Finalized" />
</PollFolder>
</div>
);
}
Loading

2 comments on commit a1bac0c

@vercel
Copy link

@vercel vercel bot commented on a1bac0c Jan 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on a1bac0c Jan 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

app – ./

app-rallly.vercel.app
app-git-main-rallly.vercel.app
app.rallly.co

Please sign in to comment.