Skip to content

Commit

Permalink
fix: form typing and error handling in auth components
Browse files Browse the repository at this point in the history
- Add proper TypeScript form event typing in SignInForm
- Fix form input value access using elements.namedItem
- Add error message handling in catch block
- Create DashboardNav component for navigation
  • Loading branch information
while-basic committed Dec 18, 2024
1 parent d64555d commit fc73ed0
Show file tree
Hide file tree
Showing 13 changed files with 338 additions and 168 deletions.
8 changes: 1 addition & 7 deletions app/resume/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { Button } from "@/components/ui/button"
import { Card } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Download, Mail, Github, Linkedin } from "lucide-react"
import { Download, Github, Linkedin } from "lucide-react"
import { CodeIcon, GlobeIcon, Settings2Icon, BotIcon, WrenchIcon } from "@/components/icons"
import { AudioPlayer } from "@/components/ui/audio-player"
import { Breadcrumb } from "@/components/breadcrumb"
Expand All @@ -17,12 +17,6 @@ export default function ResumePage() {
<h1 className="text-4xl font-bold mb-2">Christopher Celaya</h1>
<p className="text-xl mb-6 text-muted-foreground">Mechatronic Technician | Software Developer | Audio Engineer</p>
<div className="flex flex-wrap gap-4">
<Button variant="outline" size="sm" asChild>
<a href="tel:915-279-0197">
<Mail className="mr-2 h-4 w-4" />
915-279-0197
</a>
</Button>
<Button variant="outline" size="sm" asChild>
<a href="https://github.com/while-basic" target="_blank" rel="noopener noreferrer">
<Github className="mr-2 h-4 w-4" />
Expand Down
116 changes: 116 additions & 0 deletions app/services/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
'use client';

import { Footer } from "@/components/footer";
import { withClientBoundary } from "@/components/client-wrapper";
import { ArrowLeftRight, Laptop, Cog, Server } from "lucide-react";

function ServicesPage() {
return (
<div className="min-h-screen bg-black">
{/* Header */}
<section className="container mx-auto pt-32 pb-16 px-4">
<div className="max-w-4xl mx-auto text-center">
<h1 className="text-5xl font-bold mb-6 text-white">Services</h1>
<p className="text-xl text-gray-400 mb-12">
Driving innovation through mechatronics, data center operations, and software development.
</p>
</div>
</section>

{/* Services Sections */}
<div className="container mx-auto px-4 pb-24">
{/* Data Center Operations */}
<section id="data-center" className="mb-24">
<div className="max-w-4xl mx-auto">
<div className="flex items-center gap-4 mb-6">
<Server className="w-8 h-8 text-white" />
<h2 className="text-3xl font-bold text-white">Data Center Operations</h2>
</div>
<p className="text-gray-400 text-lg mb-6">
Ensuring optimal performance and uptime for critical and non-critical data center infrastructure.
</p>
<div className="bg-zinc-900 rounded-lg p-6">
<h3 className="text-xl font-semibold text-white mb-4">Services Include:</h3>
<ul className="text-gray-400 space-y-3">
<li>• Preventive maintenance for electrical and mechanical systems</li>
<li>• CMMS-based task and workflow management</li>
<li>• Emergency response and contractor supervision</li>
<li>• Data center infrastructure troubleshooting and optimization</li>
</ul>
</div>
</div>
</section>

{/* Mechatronics & Industrial Maintenance */}
<section id="mechatronics" className="mb-24">
<div className="max-w-4xl mx-auto">
<div className="flex items-center gap-4 mb-6">
<Cog className="w-8 h-8 text-white" />
<h2 className="text-3xl font-bold text-white">Mechatronics & Industrial Maintenance</h2>
</div>
<p className="text-gray-400 text-lg mb-6">
Maintaining and repairing complex industrial systems to ensure operational excellence.
</p>
<div className="bg-zinc-900 rounded-lg p-6">
<h3 className="text-xl font-semibold text-white mb-4">Expertise:</h3>
<ul className="text-gray-400 space-y-3">
<li>• Pneumatic and hydraulic systems maintenance</li>
<li>• Electrical troubleshooting and system optimization</li>
<li>• Preventive maintenance programs</li>
<li>• Cooling and water system management</li>
</ul>
</div>
</div>
</section>

{/* Software Development */}
<section id="software" className="mb-24">
<div className="max-w-4xl mx-auto">
<div className="flex items-center gap-4 mb-6">
<Laptop className="w-8 h-8 text-white" />
<h2 className="text-3xl font-bold text-white">Software Development</h2>
</div>
<p className="text-gray-400 text-lg mb-6">
Building robust and innovative software solutions to tackle industry challenges.
</p>
<div className="bg-zinc-900 rounded-lg p-6">
<h3 className="text-xl font-semibold text-white mb-4">Specializations:</h3>
<ul className="text-gray-400 space-y-3">
<li>• Web application development using Next.js and React</li>
<li>• AI and machine learning integration</li>
<li>• API development and systems integration</li>
<li>• Cloud-based application deployment</li>
</ul>
</div>
</div>
</section>

{/* Project Management */}
<section id="project-management" className="mb-24">
<div className="max-w-4xl mx-auto">
<div className="flex items-center gap-4 mb-6">
<ArrowLeftRight className="w-8 h-8 text-white" />
<h2 className="text-3xl font-bold text-white">Project Management</h2>
</div>
<p className="text-gray-400 text-lg mb-6">
Applying a methodical approach to drive projects from inception to completion efficiently.
</p>
<div className="bg-zinc-900 rounded-lg p-6">
<h3 className="text-xl font-semibold text-white mb-4">Key Focus Areas:</h3>
<ul className="text-gray-400 space-y-3">
<li>• Workflow optimization and task delegation</li>
<li>• Cross-disciplinary collaboration</li>
<li>• Technical documentation and quality assurance</li>
<li>• Risk assessment and mitigation</li>
</ul>
</div>
</div>
</section>
</div>

<Footer />
</div>
);
}

export default withClientBoundary(ServicesPage);
99 changes: 53 additions & 46 deletions components/auth/sign-in-form.tsx
Original file line number Diff line number Diff line change
@@ -1,65 +1,72 @@
"use client"

import { useState } from 'react'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { signInWithEmail } from '@/lib/auth'
import { useRouter } from 'next/navigation'
import { signIn } from "next-auth/react"
import { useRouter } from "next/navigation"
import { useState } from "react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { useToast } from "@/components/ui/use-toast"

export function SignInForm() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState('')
const [loading, setLoading] = useState(false)
const router = useRouter()
const { toast } = useToast()
const [isLoading, setIsLoading] = useState(false)

const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault()
setLoading(true)
setIsLoading(true)

try {
const { error } = await signInWithEmail(email, password)
if (error) throw error
const result = await signIn("credentials", {
email: (event.currentTarget.elements.namedItem('email') as HTMLInputElement).value,
password: (event.currentTarget.elements.namedItem('password') as HTMLInputElement).value,
redirect: false,
})

if (result?.error) {
toast({
title: "Error",
description: "Invalid credentials",
variant: "destructive",
})
return
}

// Successful sign in - redirect to dashboard
router.push("/dashboard")
router.refresh()

} catch (error: unknown) {
if (error instanceof Error) {
setError(error.message)
} else {
setError("An unexpected error occurred")
}
toast({
title: "Error",
description: error instanceof Error ? error.message : "Something went wrong. Please try again.",
variant: "destructive",
})
} finally {
setLoading(false)
setIsLoading(false)
}
}

return (
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
placeholder="Enter your email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="password">Password</Label>
<Input
id="password"
type="password"
placeholder="Enter your password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
</div>
{error && <p className="text-sm text-red-500">{error}</p>}
<Button type="submit" disabled={loading} className="w-full">
{loading ? 'Signing in...' : 'Sign In'}
<form onSubmit={onSubmit} className="space-y-4">
<Input
name="email"
placeholder="[email protected]"
type="email"
autoCapitalize="none"
autoComplete="email"
autoCorrect="off"
disabled={isLoading}
/>
<Input
name="password"
placeholder="Password"
type="password"
autoComplete="current-password"
disabled={isLoading}
/>
<Button type="submit" className="w-full" disabled={isLoading}>
{isLoading ? "Signing in..." : "Sign in"}
</Button>
</form>
)
Expand Down
41 changes: 41 additions & 0 deletions components/dashboard/nav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use client'

import Link from "next/link"
import { usePathname } from "next/navigation"
import { cn } from "@/lib/utils"

const navItems = [
{
title: "Overview",
href: "/dashboard",
},
{
title: "Analytics",
href: "/dashboard/analytics",
},
{
title: "Settings",
href: "/dashboard/settings",
},
]

export function DashboardNav() {
const pathname = usePathname()

return (
<nav className="grid items-start gap-2">
{navItems.map((item, index) => (
<Link
key={index}
href={item.href}
className={cn(
"flex items-center space-x-3 rounded-lg px-3 py-2 text-sm font-medium hover:bg-accent",
pathname === item.href ? "bg-accent" : "transparent"
)}
>
<span>{item.title}</span>
</Link>
))}
</nav>
)
}
7 changes: 7 additions & 0 deletions components/dashboard/user-account-nav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function UserAccountNav() {
return (
<nav>
{/* Add your user account navigation items here */}
</nav>
)
}
9 changes: 0 additions & 9 deletions components/footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,6 @@ export function Footer() {
{/* <li><Link href="/blog" className="hover:text-white">Blog</Link></li> */}
</ul>
</div>
<div className="space-y-4">
<h4 className="text-lg font-semibold text-white">Resources</h4>
<ul className="space-y-2 text-gray-400">
<li><Link href="/resume.pdf" className="hover:text-white">Resume</Link></li>
<li><Link href="/case-studies" className="hover:text-white">Case Studies</Link></li>
<li><Link href="/gallery" className="hover:text-white">Gallery</Link></li>
{/* <li><Link href="/chat" className="hover:text-white">Chat</Link></li> */}
</ul>
</div>
<div className="space-y-4">
<h4 className="text-lg font-semibold text-white">Connect</h4>
<div className="flex space-x-4">
Expand Down
22 changes: 16 additions & 6 deletions components/layout-wrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,25 @@ export function LayoutWrapper({ children }: LayoutWrapperProps) {
<div className="hidden md:flex h-full w-56 flex-col fixed inset-y-0 z-40">
<Sidebar />
</div>
<main className="md:pl-56 pt-[60px] min-h-screen pb-20">
<Suspense fallback={<div>Loading...</div>}>
{children}
</Suspense>
<main className="md:pl-56 pt-[60px] min-h-[calc(100vh-60px)] pb-20 px-4 md:px-8">
<div className="max-w-6xl mx-auto">
<Suspense
fallback={
<div className="flex items-center justify-center min-h-[60vh]">
<div className="animate-pulse">Loading...</div>
</div>
}
>
{children}
</Suspense>
</div>
</main>
<div className="md:pl-56 fixed bottom-0 left-0 right-0">
<div className="md:pl-56 fixed bottom-0 left-0 right-0 z-40">
<Footer />
</div>
<MobileNav />
<div className="md:hidden">
<MobileNav />
</div>
</div>
)
}
4 changes: 2 additions & 2 deletions components/loading-screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import { useEffect, useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';

export function LoadingScreen() {
const [isLoading, setIsLoading] = useState(true);
const [dimensions, setDimensions] = useState({
Expand Down Expand Up @@ -32,7 +31,7 @@ export function LoadingScreen() {
// Hide loading screen after 1.0 seconds
const timer = setTimeout(() => {
setIsLoading(false);
}, 1000);
}, 2000);

return () => clearTimeout(timer);
}, []);
Expand Down Expand Up @@ -134,3 +133,4 @@ export function LoadingScreen() {
</AnimatePresence>
);
}

Loading

0 comments on commit fc73ed0

Please sign in to comment.