fix: landing navbar not sticky to top, fix onboarding UI
This commit is contained in:
@@ -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">
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user