← back to thosor87__sosoapp

Function bodies 60 total

All specs Real LLM only Function bodies
validateStep2 function · typescript · L30-L42 (13 LOC)
src/features/registration/validation.ts
export function validateStep2(data: Step2Data): ValidationResult {
  const errors: Record<string, string> = {}

  if (data.food.bringsCake && !data.food.cakeDescription.trim()) {
    errors.cakeDescription = 'Bitte beschreibe den Kuchen'
  }

  if (data.food.bringsSalad && !data.food.saladDescription.trim()) {
    errors.saladDescription = 'Bitte beschreibe den Salat'
  }

  return { valid: Object.keys(errors).length === 0, errors }
}
validateStep3 function · typescript · L46-L54 (9 LOC)
src/features/registration/validation.ts
export function validateStep3(data: Step3Data): ValidationResult {
  const errors: Record<string, string> = {}

  if (data.camping.wantsCamping && data.camping.tentCount < 1) {
    errors.tentCount = 'Mindestens 1 Zelt erforderlich'
  }

  return { valid: Object.keys(errors).length === 0, errors }
}
TimelineNode function · typescript · L24-L129 (106 LOC)
src/features/timeline/components/TimelineDisplay.tsx
function TimelineNode({
  item,
  index,
  isLast,
}: {
  item: TimelineItem
  index: number
  isLast: boolean
}) {
  const ref = useRef<HTMLDivElement>(null)
  const isInView = useInView(ref, { once: true, margin: '-50px' })
  const isEven = index % 2 === 0
  const colors = CATEGORY_COLOR_MAP[item.category]

  return (
    <div ref={ref} className="relative flex items-start">
      {/* Desktop layout: alternating sides */}
      {/* Left content (desktop only) */}
      <div className="hidden md:flex flex-1 justify-end pr-8">
        {isEven && (
          <motion.div
            initial={{ opacity: 0, x: -30 }}
            animate={isInView ? { opacity: 1, x: 0 } : {}}
            transition={{ duration: 0.5, delay: 0.1 }}
            className="max-w-sm text-right"
          >
            <TimelineCard item={item} colors={colors} align="right" />
          </motion.div>
        )}
      </div>

      {/* Center line + dot (desktop) */}
      <div className="hidden md:flex flex-col i
TimelineCard function · typescript · L131-L169 (39 LOC)
src/features/timeline/components/TimelineDisplay.tsx
function TimelineCard({
  item,
  colors,
  align,
}: {
  item: TimelineItem
  colors: { bg: string; text: string; dot: string }
  align: 'left' | 'right'
}) {
  return (
    <div
      className={cn(
        'rounded-xl border border-warm-100 bg-white p-4 shadow-sm mb-4 md:mb-0',
        align === 'right' ? 'md:text-right' : ''
      )}
    >
      <div
        className={cn(
          'flex items-center gap-2 mb-2',
          align === 'right' ? 'md:flex-row-reverse' : ''
        )}
      >
        <span
          className={cn(
            'inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-bold',
            colors.bg,
            colors.text
          )}
        >
          {item.time}
        </span>
      </div>
      <h4 className="font-semibold text-warm-800 mb-1">{item.title}</h4>
      {item.description && (
        <p className="text-sm text-warm-500">{item.description}</p>
      )}
    </div>
  )
}
TimelineDisplay function · typescript · L175-L203 (29 LOC)
src/features/timeline/components/TimelineDisplay.tsx
export function TimelineDisplay({ items }: TimelineDisplayProps) {
  const visibleItems = items.filter((item) => item.isVisible)

  if (visibleItems.length === 0) {
    return (
      <div className="rounded-2xl border border-warm-100 bg-white p-8 text-center text-warm-400">
        Der Ablaufplan wird noch erstellt.
      </div>
    )
  }

  return (
    <div className="relative">
      {/* Desktop center line (behind everything) */}
      <div className="hidden md:block absolute left-1/2 top-5 bottom-5 w-0.5 bg-warm-200 -translate-x-1/2" />

      <div className="space-y-0">
        {visibleItems.map((item, index) => (
          <TimelineNode
            key={item.id}
            item={item}
            index={index}
            isLast={index === visibleItems.length - 1}
          />
        ))}
      </div>
    </div>
  )
}
cn function · typescript · L4-L6 (3 LOC)
src/lib/utils/cn.ts
export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}
AdminPage function · typescript · L9-L68 (60 LOC)
src/pages/AdminPage.tsx
export function AdminPage() {
  const { isAdmin, loginAdmin } = useAuthStore()
  const [password, setPassword] = useState('')
  const [error, setError] = useState('')

  const handleLogin = async (e: React.FormEvent) => {
    e.preventDefault()
    const success = await loginAdmin(password)
    if (!success) {
      setError('Falsches Passwort')
      setPassword('')
    }
  }

  if (!isAdmin) {
    return (
      <PageContainer className="flex items-center justify-center min-h-[60vh]">
        <motion.div
          initial={{ opacity: 0, y: 20 }}
          animate={{ opacity: 1, y: 0 }}
          className="w-full max-w-sm text-center"
        >
          <span className="text-4xl block mb-4">{'\u{1F512}'}</span>
          <h1 className="text-xl font-display font-bold text-warm-800 mb-2">Orga-Bereich</h1>
          <p className="text-warm-500 text-sm mb-6">
            Bitte gib das Admin-Passwort ein.
          </p>
          <form onSubmit={handleLogin} className="space-y-4">
      
Repobility analyzer · published findings · https://repobility.com
LandingPage function · typescript · L13-L232 (220 LOC)
src/pages/LandingPage.tsx
export function LandingPage() {
  const eventConfig = useAuthStore((s) => s.eventConfig)
  const eventId = useAuthStore((s) => s.eventId)
  const accessToken = useAuthStore((s) => s.accessToken)
  const addToast = useToastStore((s) => s.addToast)
  const [linkCopied, setLinkCopied] = useState(false)

  const handleCopyLink = () => {
    const url = `${window.location.origin}/?token=${accessToken}`
    navigator.clipboard.writeText(url).then(() => {
      addToast('Einladungslink kopiert!', 'success')
      setLinkCopied(true)
      setTimeout(() => setLinkCopied(false), 2000)
    }).catch(() => {
      addToast('Kopieren fehlgeschlagen', 'error')
    })
  }
  const subscribeToRegistrations = useRegistrationStore(
    (s) => s.subscribeToRegistrations
  )
  const timelineItems = useTimelineStore((s) => s.items)
  const subscribeToTimeline = useTimelineStore((s) => s.subscribeToTimeline)
  const mapData = useMapStore((s) => s.mapData)
  const subscribeToMap = useMapStore((s) => s.subscri
NotFoundPage function · typescript · L5-L26 (22 LOC)
src/pages/NotFoundPage.tsx
export function NotFoundPage() {
  return (
    <div className="min-h-[60vh] flex items-center justify-center p-4">
      <motion.div
        initial={{ opacity: 0, y: 20 }}
        animate={{ opacity: 1, y: 0 }}
        className="text-center"
      >
        <span className="text-6xl block mb-4">{'\u{1F3D6}\uFE0F'}</span>
        <h1 className="text-2xl font-display font-bold text-warm-800 mb-2">
          Seite nicht gefunden
        </h1>
        <p className="text-warm-500 mb-6">
          Diese Seite existiert leider nicht.
        </p>
        <Link to="/">
          <Button>Zur{'\u00FC'}ck zur Startseite</Button>
        </Link>
      </motion.div>
    </div>
  )
}
OverviewPage function · typescript · L11-L50 (40 LOC)
src/pages/OverviewPage.tsx
export function OverviewPage() {
  const eventId = useAuthStore((s) => s.eventId)
  const subscribeToRegistrations = useRegistrationStore(
    (s) => s.subscribeToRegistrations
  )

  useEffect(() => {
    if (!eventId) return
    const unsubscribe = subscribeToRegistrations(eventId)
    return () => unsubscribe()
  }, [eventId, subscribeToRegistrations])

  return (
    <PageContainer>
      <motion.h1
        initial={{ opacity: 0, y: 10 }}
        animate={{ opacity: 1, y: 0 }}
        className="text-3xl font-display font-bold text-warm-800 mb-6"
      >
        Übersicht
      </motion.h1>

      {/* Stat Cards */}
      <section className="mb-8">
        <StatCards />
      </section>

      {/* Registration List */}
      <section className="mb-8">
        <RegistrationList />
      </section>

      {/* Food & Camping */}
      <section className="mb-8 space-y-4">
        <FoodOverview />
        <CampingList />
      </section>
    </PageContainer>
  )
}
‹ prevpage 2 / 2