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
5 changes: 5 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ Use `pnpm w:<workspace>` shortcuts:
- **Do not** prefix your branch with your name or initials
- **NEVER commit, push, or pull** - these actions are always manual

### File Search Scope

- **NEVER search outside the current worktree** - all searches should stay within the current working directory
- The working directory is the root of the monorepo; do not traverse to parent directories or other projects

### Code Quality Standards

- Run type checking with `pnpm typecheck` or `pnpm w:app typecheck` after making changes
Expand Down
1 change: 1 addition & 0 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"build": "next build",
"build:prod": "cd ../../services/db && pnpm run migrate && cd ../../apps/api && next build",
"dev": "next dev -p 3300",
"dev:e2e": "next dev -p 4300",
"format:check": "prettier --log-level=warn --check \"**/*.{ts,tsx}\" \"!.next\"",
"start": "next start",
"typecheck": "tsgo --noEmit"
Expand Down
1 change: 1 addition & 0 deletions apps/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"build": "next build",
"check:i18n": "tsx scripts/check-missing-intl-keys.ts",
"dev": "next dev -p 3100",
"dev:e2e": "next dev -p 4100",
"format:check": "prettier --log-level=warn --check \"**/*.{ts,tsx}\" \"!.next\"",
"start": "next start -p 3100",
"typecheck": "tsgo --noEmit"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const EditDecisionPage = async ({
<ProcessBuilderSidebar navigationConfig={navigationConfig} />
<main className="grow">
<ProcessBuilderContent
decisionId={decisionProfile.id}
decisionProfileId={decisionProfile.id}
decisionName={decisionProfile.name}
navigationConfig={navigationConfig}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,31 @@ import { Suspense } from 'react';
import ErrorBoundary from '@/components/ErrorBoundary';
import { ProposalView } from '@/components/decisions/ProposalView';

const LEGACY_ORG_SLUGS = ['people-powered', 'cowop', 'one-project'];

function ProposalViewPageContent({
profileId,
slug,
}: {
profileId: string;
slug: string;
}) {
const [proposal] = trpc.decision.getProposal.useSuspenseQuery({
profileId,
});
const [[proposal, decisionProfile]] = trpc.useSuspenseQueries((t) => [
t.decision.getProposal({ profileId }),
t.decision.getDecisionBySlug({ slug }),
]);

if (!proposal) {
notFound();
}

const backHref = `/decisions/${slug}`;
const ownerSlug = decisionProfile?.processInstance?.owner?.slug;
const instanceId = decisionProfile?.processInstance?.id;

const backHref =
ownerSlug && LEGACY_ORG_SLUGS.includes(ownerSlug) && instanceId
? `/profile/${ownerSlug}/decisions/${instanceId}/`
: `/decisions/${slug}`;

return <ProposalView proposal={proposal} backHref={backHref} />;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import { ProposalView } from '@/components/decisions/ProposalView';

function ProposalViewPageContent({
profileId,
decisionSlug,
orgSlug,
instanceId,
}: {
profileId: string;
decisionSlug: string;
orgSlug: string;
instanceId: string;
}) {
const [proposal] = trpc.decision.getProposal.useSuspenseQuery({
profileId,
Expand All @@ -22,7 +24,7 @@ function ProposalViewPageContent({
notFound();
}

const backHref = `/decisions/${decisionSlug}`;
const backHref = `/profile/${orgSlug}/decisions/${instanceId}/`;

return <ProposalView proposal={proposal} backHref={backHref} />;
}
Expand Down Expand Up @@ -74,15 +76,20 @@ function ProposalViewPageSkeleton() {
}

const ProposalViewPage = () => {
const { profileId, slug } = useParams<{
const { profileId, slug, id } = useParams<{
profileId: string;
slug: string;
id: string;
}>();

return (
<ErrorBoundary>
<Suspense fallback={<ProposalViewPageSkeleton />}>
<ProposalViewPageContent profileId={profileId} decisionSlug={slug} />
<ProposalViewPageContent
profileId={profileId}
orgSlug={slug}
instanceId={id}
/>
</Suspense>
</ErrorBoundary>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const ActiveDecisionsNotificationsSuspense = () => {
<ButtonLink
size="small"
className="w-full sm:w-auto"
href={`/profile/${decision.slug}/decisions/${instance?.id}`}
href={`/decisions/${decision.slug}`}
onPress={() => setNavigatingId(decision.id)}
>
{isNavigating ? <LoadingSpinner /> : 'Participate'}
Expand Down
2 changes: 1 addition & 1 deletion apps/app/src/components/LoginPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { useSearchParams } from 'next/navigation';
import React, { useCallback } from 'react';
import { z } from 'zod';
import { create } from 'zustand';
import GoogleIcon from '~icons/logos/google-icon.jsx';
import GoogleIcon from '~icons/logos/google-icon';

import { CommonLogo } from './CommonLogo';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
'use client';

import { useUser } from '@/utils/UserProvider';

import { type SectionProps, getContentComponent } from './contentRegistry';
import { type NavigationConfig } from './navigationConfig';
import { useProcessNavigation } from './useProcessNavigation';

export function ProcessBuilderContent({
decisionId,
decisionProfileId,
decisionName,
navigationConfig,
}: SectionProps & { navigationConfig?: NavigationConfig }) {
const { currentStep, currentSection } =
useProcessNavigation(navigationConfig);

const access = useUser();
const isAdmin = access.getPermissionsForProfile(decisionProfileId).admin;

if (!isAdmin) {
throw new Error('UNAUTHORIZED');
}

const ContentComponent = getContentComponent(
currentStep?.id,
currentSection?.id,
Expand All @@ -22,6 +31,9 @@ export function ProcessBuilderContent({
}

return (
<ContentComponent decisionId={decisionId} decisionName={decisionName} />
<ContentComponent
decisionProfileId={decisionProfileId}
decisionName={decisionName}
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import FormBuilderSection from './stepContent/template/FormBuilderSection';

// Props that all section components receive
export interface SectionProps {
decisionId: string;
decisionProfileId: string;
decisionName: string;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { ProfileUsersAccess } from '@/components/decisions/ProfileUsersAccess';

import type { SectionProps } from '../../contentRegistry';

export default function MembersSection({ decisionId }: SectionProps) {
export default function MembersSection({ decisionProfileId }: SectionProps) {
return (
<div className="px-24 py-16">
<div className="mx-auto max-w-5xl">
<ProfileUsersAccess profileId={decisionId} />
<ProfileUsersAccess profileId={decisionProfileId} />
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { SectionProps } from '../../contentRegistry';

export default function RolesSection({
decisionId,
decisionProfileId,
decisionName,
}: SectionProps) {
return (
<div className="p-4 sm:p-8">
<h2 className="text-xl font-semibold">Roles &amp; Permissions</h2>
<p className="text-neutral-gray4">Decision: {decisionName}</p>
<p className="text-neutral-gray4">ID: {decisionId}</p>
<p className="text-neutral-gray4">ID: {decisionProfileId}</p>
{/* TODO: Implement roles and permissions configuration */}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { SectionProps } from '../../contentRegistry';

export default function OverviewSection({
decisionId,
decisionProfileId,
decisionName,
}: SectionProps) {
return (
<div className="p-4 sm:p-8">
<h2 className="text-xl font-semibold">Overview</h2>
<p className="text-neutral-gray4">Decision: {decisionName}</p>
<p className="text-neutral-gray4">ID: {decisionId}</p>
<p className="text-neutral-gray4">ID: {decisionProfileId}</p>
<p className="max-w-128">
Cupidatat pariatur irure et labore quis aliquip ullamco. Laboris
cupidatat amet duis deserunt reprehenderit. Voluptate duis qui Lorem
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { SectionProps } from '../../contentRegistry';

export default function PhasesSection({
decisionId,
decisionProfileId,
decisionName,
}: SectionProps) {
return (
<div className="p-4 sm:p-8">
<h2 className="text-xl font-semibold">Phases</h2>
<p className="text-neutral-gray4">Decision: {decisionName}</p>
<p className="text-neutral-gray4">ID: {decisionId}</p>
<p className="text-neutral-gray4">ID: {decisionProfileId}</p>
{/* TODO: Implement phases configuration */}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { SectionProps } from '../../contentRegistry';

export default function ProposalCategoriesSection({
decisionId,
decisionProfileId,
decisionName,
}: SectionProps) {
return (
<div className="p-4 sm:p-8">
<h2 className="text-xl font-semibold">Proposal Categories</h2>
<p className="text-neutral-gray4">Decision: {decisionName}</p>
<p className="text-neutral-gray4">ID: {decisionId}</p>
<p className="text-neutral-gray4">ID: {decisionProfileId}</p>
{/* TODO: Implement proposal categories configuration */}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { SectionProps } from '../../contentRegistry';

export default function VotingSection({
decisionId,
decisionProfileId,
decisionName,
}: SectionProps) {
return (
<div className="p-4 sm:p-8">
<h2 className="text-xl font-semibold">Voting</h2>
<p className="text-neutral-gray4">Decision: {decisionName}</p>
<p className="text-neutral-gray4">ID: {decisionId}</p>
<p className="text-neutral-gray4">ID: {decisionProfileId}</p>
{/* TODO: Implement voting configuration */}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { SectionProps } from '../../contentRegistry';

export default function CriteriaSection({
decisionId,
decisionProfileId,
decisionName,
}: SectionProps) {
return (
<div className="p-4 sm:p-8">
<h2 className="text-xl font-semibold">Criteria</h2>
<p className="text-neutral-gray4">Decision: {decisionName}</p>
<p className="text-neutral-gray4">ID: {decisionId}</p>
<p className="text-neutral-gray4">ID: {decisionProfileId}</p>
{/* TODO: Implement rubric criteria configuration */}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { SectionProps } from '../../contentRegistry';

export default function SettingsSection({
decisionId,
decisionProfileId,
decisionName,
}: SectionProps) {
return (
<div className="p-4 sm:p-8">
<h2 className="text-xl font-semibold">Settings</h2>
<p className="text-neutral-gray4">Decision: {decisionName}</p>
<p className="text-neutral-gray4">ID: {decisionId}</p>
<p className="text-neutral-gray4">ID: {decisionProfileId}</p>
{/* TODO: Implement rubric settings configuration */}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { SectionProps } from '../../contentRegistry';

export default function FormBuilderSection({
decisionId,
decisionProfileId,
decisionName,
}: SectionProps) {
return (
<div className="p-4 sm:p-8">
<h2 className="text-title-base font-semibold">Form Builder</h2>
<p className="text-neutral-gray4">Decision: {decisionName}</p>
<p className="text-neutral-gray4">ID: {decisionId}</p>
<p className="text-neutral-gray4">ID: {decisionProfileId}</p>
{/* TODO: Implement form builder with custom sidebar */}
</div>
);
Expand Down
Loading
Loading