fix: landing navbar not sticky to top, fix onboarding UI

This commit is contained in:
Hafid Nur
2025-11-26 14:33:17 +07:00
parent 19aa5bb452
commit 7e385c6385
5 changed files with 38 additions and 24 deletions
+27 -16
View File
@@ -14,6 +14,7 @@ import {
import { zodResolver } from '@hookform/resolvers/zod';
import { CitySelect } from '../../../components/city-select';
import { Icon } from '@iconify/react';
const ROLE_OPTIONS = [
'Frontend Developer',
@@ -69,19 +70,19 @@ const UserOnboardingPage: FC = (): ReactElement => {
const onSubmit = form.handleSubmit(async (data) => {
try {
console.log('[Onboarding] Starting submission...', data);
// console.log('[Onboarding] Starting submission...', data);
let avatarUrl = session?.user?.avatar || null;
// Upload avatar if a new file was selected
if (avatarFile) {
console.log('[Onboarding] Uploading avatar...');
// console.log('[Onboarding] Uploading avatar...');
const uploadResult = await uploadAvatar(avatarFile);
avatarUrl = uploadResult.data.url;
console.log('[Onboarding] Avatar uploaded:', avatarUrl);
// console.log('[Onboarding] Avatar uploaded:', avatarUrl);
}
// Update user in Supabase
console.log('[Onboarding] Updating user in Supabase...');
// console.log('[Onboarding] Updating user in Supabase...');
const result = await updateUser({
fullname: data.fullname,
avatar: avatarUrl,
@@ -89,17 +90,17 @@ const UserOnboardingPage: FC = (): ReactElement => {
bio: data.bio,
skills: data.skills,
});
console.log('[Onboarding] User updated successfully:', result);
// console.log('[Onboarding] User updated successfully:', result);
// Wait a bit for the onSuccess handler to update localStorage
// The updateUser mutation's onSuccess handler updates the Zustand store and localStorage
await new Promise((resolve) => setTimeout(resolve, 100));
console.log('[Onboarding] Navigating to dashboard...');
// console.log('[Onboarding] Navigating to dashboard...');
// Use window.location for a full page reload to ensure middleware sees updated localStorage
globalThis.location.href = '/dashboard';
} catch (error) {
console.error('[Onboarding] Onboarding failed:', error);
// console.error('[Onboarding] Onboarding failed:', error);
alert(
`Onboarding failed: ${
error instanceof Error ? error.message : 'Unknown error'
@@ -115,7 +116,7 @@ const UserOnboardingPage: FC = (): ReactElement => {
<h1 className="text-3xl font-bold text-gray-900 mb-2">
Complete Your Profile
</h1>
<p className="text-gray-600">
<p className="text-gray-600 font-sans">
Tell us more about yourself to get started
</p>
</div>
@@ -132,13 +133,19 @@ const UserOnboardingPage: FC = (): ReactElement => {
/>
) : (
<div className="w-32 h-32 rounded-full bg-gray-200 flex items-center justify-center">
<span className="text-gray-400 text-4xl">👤</span>
{/* <span className="text-gray-400 text-4xl">👤</span> */}
<Icon
icon="ic:baseline-person"
width="48"
height="48"
className="text-gray-400"
/>
</div>
)}
</div>
<div>
<div className="flex flex-col items-center">
<label htmlFor="avatar" className="cursor-pointer">
<span className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 inline-block">
<span className="px-4 py-2 bg-primary-500 text-white rounded-lg hover:bg-primary-600 inline-block">
{avatarPreview ? 'Change Photo' : 'Upload Photo'}
</span>
<input
@@ -161,11 +168,14 @@ const UserOnboardingPage: FC = (): ReactElement => {
label="Full Name"
placeholder="Enter your full name"
name="fullname"
className="px-3 py-2 text-label2 rounded-lg max-h-auto text-base"
size="md"
isRequired={true}
/>
{/* City */}
<div className="space-y-2">
<label className="block text-sm font-medium text-gray-700">
<label className="block text-base font-medium text-gray-700">
City <span className="text-red-500">*</span>
</label>
<Controller
@@ -184,7 +194,7 @@ const UserOnboardingPage: FC = (): ReactElement => {
{/* Role/Skills */}
<div className="space-y-2">
<label className="block text-sm font-medium text-gray-700">
<label className="block text-base font-medium text-gray-700">
Role / Skills
</label>
<Controller
@@ -220,19 +230,20 @@ const UserOnboardingPage: FC = (): ReactElement => {
{/* Bio */}
<div className="space-y-2">
<label className="block text-sm font-medium text-gray-700">
<label className="block text-base font-medium text-gray-700">
Bio <span className="text-gray-400">(Optional)</span>
</label>
<Controller
control={form.control}
name="bio"
render={({ field, fieldState }) => (
<div>
<div className="flex">
<Textarea
{...field}
placeholder="Tell us about yourself..."
rows={4}
className="w-full"
className="w-full rounded-lg text-sm"
style={{ resize: 'vertical' }}
/>
{fieldState.error && (
<p className="text-sm text-red-500 mt-1">
+4 -4
View File
@@ -62,7 +62,7 @@ export default function HomePage() {
];
return (
<div className="min-h-screen bg-white">
<main className="min-h-screen bg-white">
{/* Navigation */}
<div id="#top" className="hidden"></div>
<nav className="border-b border-gray-200 bg-white sticky top-0 z-50">
@@ -136,7 +136,7 @@ export default function HomePage() {
{/* Mobile Menu */}
{mobileMenuOpen && (
<div className="md:hidden border-b border-gray-200 bg-white">
<nav className="md:hidden sticky top-18 border-b border-gray-200 bg-white z-40">
<div className="flex flex-col items-start gap-4 px-4 py-4">
<a
href="#timeline"
@@ -163,7 +163,7 @@ export default function HomePage() {
Daftar Sekarang
</button>
</div>
</div>
</nav>
)}
{/* Hero Section */}
@@ -792,6 +792,6 @@ export default function HomePage() {
</div>
</div>
</footer>
</div>
</main>
);
}
@@ -78,7 +78,7 @@ export const CitySelect: FC<CitySelectProps> = ({
<button
type="button"
onClick={handleClearSelection}
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600"
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 cursor-pointer"
>
</button>
@@ -88,7 +88,7 @@ export const CitySelect: FC<CitySelectProps> = ({
{error && <p className="text-sm text-red-500 mt-1">{error}</p>}
{isOpen && (
<div className="absolute z-50 w-full mt-1 bg-white border border-gray-300 rounded-lg shadow-lg max-h-60 overflow-y-auto">
<div className="absolute z-50 w-full mt-1 bg-white border border-gray-300 rounded-lg shadow-lg max-h-60 overflow-y-auto text-label2">
{filteredCities.length > 0 ? (
<ul className="py-1">
{filteredCities.map((city) => (
@@ -20,6 +20,7 @@ export type TInputFieldProps = Omit<
disabled?: boolean;
helperText?: string;
htmlFor?: string;
isRequired?: boolean;
};
const sizeClasses: Record<TInputSize, { label: string; helperText: string }> = {
@@ -47,6 +48,7 @@ export const InputField: FC<TInputFieldProps> = ({
htmlFor,
className,
disabled,
isRequired = false,
...rest
}): ReactElement => {
return (
@@ -58,7 +60,7 @@ export const InputField: FC<TInputFieldProps> = ({
sizeClasses[size].label
)}
>
{label}
{label} {isRequired ? <span className="text-red-500">*</span> : null}
</label>
<Input
{...(htmlFor && { id: htmlFor })}
@@ -75,7 +77,7 @@ export const InputField: FC<TInputFieldProps> = ({
{...rest}
/>
{error ? (
<p className="text-danger-500 text-label1 text-left">{error}</p>
<p className="text-danger-500 text-label2 text-left">{error}</p>
) : (
helperText && (
<p
@@ -39,6 +39,7 @@ export const ControlledInputField = <T extends FieldValues>(
error={fieldState.error?.message}
{...inputProps}
onChange={handleChange}
isRequired={props.isRequired}
/>
);
};