Skip to content

Commit 6b62325

Browse files
Merge pull request #10 from Sachinchaurasiya360/development
fix layout in phone
2 parents bb51747 + ed64bc7 commit 6b62325

25 files changed

Lines changed: 499 additions & 246 deletions

client/src/components/StudentSidebar.tsx

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { useState } from "react";
22
import { NavLink, Link, useNavigate } from "react-router";
3-
import { Briefcase, FileText, LogOut, ScanSearch, Building2, ChevronsLeft, ChevronsRight, UserCircle, Award, Globe, Crown, ShieldCheck, Video, GraduationCap, User, Menu, X } from "lucide-react";
3+
import { Briefcase, FileText, LogOut, ScanSearch, Building2, ChevronsLeft, ChevronsRight, UserCircle, Award, Globe, Crown, ShieldCheck, Video, GraduationCap, User, Menu, X, Sun, Moon } from "lucide-react";
44
import { useAuthStore } from "../lib/auth.store";
5+
import { useThemeStore } from "../lib/theme.store";
56

67
const NAV_ITEMS = [
78
{ to: "/student/jobs", icon: Briefcase, label: "Browse Jobs" },
@@ -19,6 +20,7 @@ const NAV_ITEMS = [
1920

2021
export function useStudentSidebar() {
2122
const { user, logout } = useAuthStore();
23+
const { theme, toggleTheme } = useThemeStore();
2224
const isPremium = user?.subscriptionStatus === "ACTIVE" && user.subscriptionPlan !== "FREE";
2325
const navigate = useNavigate();
2426
const [collapsed, setCollapsed] = useState(() => {
@@ -46,17 +48,36 @@ export function useStudentSidebar() {
4648
const sidebar = (
4749
<>
4850
{/* Mobile top bar */}
49-
<div className="fixed top-0 left-0 right-0 z-40 lg:hidden bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-800 px-4 py-3 flex items-center gap-3">
50-
<button
51-
onClick={() => setMobileOpen(true)}
52-
className="p-1.5 rounded-lg text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
53-
>
54-
<Menu className="w-5 h-5" />
55-
</button>
56-
<Link to="/" className="flex items-center gap-2 no-underline">
57-
<img src="/logo.png" alt="InternHack" className="h-7 w-7 rounded-lg object-contain" />
58-
<span className="text-base font-bold text-gray-950 dark:text-white">InternHack</span>
59-
</Link>
51+
<div className="fixed top-0 left-0 right-0 z-40 lg:hidden bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-800 px-4 py-3 flex items-center justify-between">
52+
<div className="flex items-center gap-3">
53+
<button
54+
onClick={() => setMobileOpen(true)}
55+
className="p-1.5 rounded-lg text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
56+
>
57+
<Menu className="w-5 h-5" />
58+
</button>
59+
<Link to="/" className="flex items-center gap-2 no-underline">
60+
<img src="/logo.png" alt="InternHack" className="h-7 w-7 rounded-lg object-contain" />
61+
<span className="text-base font-bold text-gray-950 dark:text-white">InternHack</span>
62+
</Link>
63+
</div>
64+
<div className="flex items-center gap-2">
65+
<button
66+
onClick={toggleTheme}
67+
className="p-2 text-gray-500 dark:text-gray-400 hover:text-gray-950 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg transition-colors"
68+
>
69+
{theme === "dark" ? <Sun className="w-4 h-4" /> : <Moon className="w-4 h-4" />}
70+
</button>
71+
<Link to="/student/profile" className="no-underline">
72+
{user?.profilePic && !imgError ? (
73+
<img src={user.profilePic} alt={user.name} className="w-8 h-8 rounded-full object-cover" onError={() => setImgError(true)} />
74+
) : (
75+
<div className="w-8 h-8 rounded-full bg-gray-100 dark:bg-gray-800 flex items-center justify-center">
76+
<User className="w-4 h-4 text-gray-500 dark:text-gray-400" />
77+
</div>
78+
)}
79+
</Link>
80+
</div>
6081
</div>
6182

6283
{/* Mobile overlay */}

client/src/module/admin/external-jobs/AdminExternalJobsPage.tsx

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { useState } from "react";
1+
import { useState, useCallback } from "react";
22
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
3-
import { Plus, Pencil, Trash2, ExternalLink, X, Loader2, Link2 } from "lucide-react";
3+
import { Plus, Pencil, Trash2, ExternalLink, X, Loader2, Link2, Braces } from "lucide-react";
44
import api from "../../../lib/axios";
55
import toast from "react-hot-toast";
66

@@ -30,6 +30,37 @@ export default function AdminExternalJobsPage() {
3030
const [showForm, setShowForm] = useState(false);
3131
const [editingId, setEditingId] = useState<number | null>(null);
3232
const [form, setForm] = useState(EMPTY_FORM);
33+
const [jsonInput, setJsonInput] = useState("");
34+
const [jsonError, setJsonError] = useState("");
35+
36+
const parseJsonInput = useCallback((raw: string) => {
37+
setJsonInput(raw);
38+
setJsonError("");
39+
if (!raw.trim()) return;
40+
try {
41+
const obj = JSON.parse(raw);
42+
if (typeof obj !== "object" || obj === null) {
43+
setJsonError("Expected a JSON object");
44+
return;
45+
}
46+
const str = (key: string) => (typeof obj[key] === "string" ? obj[key] : "");
47+
const tags = Array.isArray(obj.tags)
48+
? obj.tags.join(", ")
49+
: typeof obj.tags === "string" ? obj.tags : "";
50+
setForm({
51+
company: str("company"),
52+
role: str("role") || str("title") || str("position"),
53+
description: str("description") || str("desc") || str("about"),
54+
salary: str("salary") || str("stipend") || str("compensation") || str("ctc"),
55+
location: str("location") || str("city"),
56+
applyLink: str("applyLink") || str("apply_link") || str("url") || str("link"),
57+
tags,
58+
});
59+
toast.success("Fields populated from JSON");
60+
} catch {
61+
setJsonError("Invalid JSON — check syntax");
62+
}
63+
}, []);
3364

3465
const { data, isLoading } = useQuery({
3566
queryKey: ["admin-external-jobs", page, search],
@@ -87,6 +118,8 @@ export default function AdminExternalJobsPage() {
87118
setShowForm(false);
88119
setEditingId(null);
89120
setForm(EMPTY_FORM);
121+
setJsonInput("");
122+
setJsonError("");
90123
};
91124

92125
const openEdit = (job: AdminJob) => {
@@ -131,11 +164,33 @@ export default function AdminExternalJobsPage() {
131164
{/* Form Modal */}
132165
{showForm && (
133166
<div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4" onClick={closeForm}>
134-
<div className="bg-white dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-700 p-6 w-full max-w-lg space-y-4" onClick={(e) => e.stopPropagation()}>
167+
<div className="bg-white dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-700 p-6 w-full max-w-lg space-y-4 max-h-[90vh] overflow-y-auto" onClick={(e) => e.stopPropagation()}>
135168
<div className="flex items-center justify-between">
136169
<h2 className="text-lg font-bold dark:text-white">{editingId ? "Edit Job" : "Add External Job"}</h2>
137170
<button onClick={closeForm} className="text-gray-400 hover:text-gray-600"><X className="w-5 h-5" /></button>
138171
</div>
172+
{/* JSON quick-fill */}
173+
{!editingId && (
174+
<div>
175+
<label className="flex items-center gap-1.5 text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">
176+
<Braces className="w-3.5 h-3.5" /> Paste JSON to auto-fill
177+
</label>
178+
<textarea
179+
value={jsonInput}
180+
onChange={(e) => parseJsonInput(e.target.value)}
181+
placeholder={'{\n "company": "Google",\n "role": "SDE Intern",\n "description": "...",\n "salary": "50k/month",\n "location": "Bangalore",\n "applyLink": "https://...",\n "tags": ["React", "Remote"]\n}'}
182+
className={`w-full px-3 py-2 text-xs font-mono border rounded-lg dark:bg-gray-800 dark:text-white focus:outline-none focus:ring-2 ${
183+
jsonError
184+
? "border-red-400 dark:border-red-500 focus:ring-red-300/30"
185+
: "border-gray-300 dark:border-gray-600 focus:ring-black/20 dark:focus:ring-white/20"
186+
}`}
187+
rows={4}
188+
/>
189+
{jsonError && <p className="text-xs text-red-500 mt-1">{jsonError}</p>}
190+
<div className="border-b border-gray-200 dark:border-gray-700 mt-3" />
191+
</div>
192+
)}
193+
139194
<Input label="Company" value={form.company} onChange={(v) => setForm({ ...form, company: v })} placeholder="e.g. Google" />
140195
<Input label="Role" value={form.role} onChange={(v) => setForm({ ...form, role: v })} placeholder="e.g. Software Engineer Intern" />
141196
<div>

client/src/module/recruiter/RecruiterLayout.tsx

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { useState } from "react";
2-
import { NavLink, Outlet, useNavigate } from "react-router";
3-
import { LayoutDashboard, Briefcase, PlusCircle, Search, LogOut, ChevronsLeft, ChevronsRight, Home, Users, School, User, Menu, X } from "lucide-react";
2+
import { NavLink, Link, Outlet, useNavigate } from "react-router";
3+
import { LayoutDashboard, Briefcase, PlusCircle, Search, LogOut, ChevronsLeft, ChevronsRight, Home, Users, School, User, Menu, X, Sun, Moon } from "lucide-react";
44
import { useAuthStore } from "../../lib/auth.store";
5+
import { useThemeStore } from "../../lib/theme.store";
56
import { Navbar } from "../../components/Navbar";
67
import { SEO } from "../../components/SEO";
78

@@ -18,6 +19,7 @@ const NAV_ITEMS = [
1819

1920
export default function RecruiterLayout() {
2021
const { user, logout } = useAuthStore();
22+
const { theme, toggleTheme } = useThemeStore();
2123
const navigate = useNavigate();
2224
const [collapsed, setCollapsed] = useState(() => {
2325
return localStorage.getItem("recruiter-sidebar-collapsed") === "true";
@@ -48,14 +50,30 @@ export default function RecruiterLayout() {
4850
</div>
4951

5052
{/* Mobile top bar */}
51-
<div className="fixed top-0 left-0 right-0 z-40 lg:hidden bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-800 px-4 py-3 flex items-center gap-3">
52-
<button
53-
onClick={() => setMobileOpen(true)}
54-
className="p-1.5 rounded-lg text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
55-
>
56-
<Menu className="w-5 h-5" />
57-
</button>
58-
<span className="text-sm font-bold text-gray-900 dark:text-white truncate">{user?.company || "Recruiter"}</span>
53+
<div className="fixed top-0 left-0 right-0 z-40 lg:hidden bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-800 px-4 py-3 flex items-center justify-between">
54+
<div className="flex items-center gap-3">
55+
<button
56+
onClick={() => setMobileOpen(true)}
57+
className="p-1.5 rounded-lg text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
58+
>
59+
<Menu className="w-5 h-5" />
60+
</button>
61+
<Link to="/" className="flex items-center gap-2 no-underline">
62+
<img src="/logo.png" alt="InternHack" className="h-7 w-7 rounded-lg object-contain" />
63+
<span className="text-base font-bold text-gray-950 dark:text-white">InternHack</span>
64+
</Link>
65+
</div>
66+
<div className="flex items-center gap-2">
67+
<button
68+
onClick={toggleTheme}
69+
className="p-2 text-gray-500 dark:text-gray-400 hover:text-gray-950 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg transition-colors"
70+
>
71+
{theme === "dark" ? <Sun className="w-4 h-4" /> : <Moon className="w-4 h-4" />}
72+
</button>
73+
<div className="w-8 h-8 rounded-full bg-gray-900 dark:bg-white text-white dark:text-gray-900 flex items-center justify-center text-sm font-bold">
74+
{user?.name?.charAt(0)?.toUpperCase() ?? "R"}
75+
</div>
76+
</div>
5977
</div>
6078

6179
{/* Mobile overlay */}

client/src/module/student/ats/AtsToolsNav.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export default function AtsToolsNav({ delay = 0.1 }: { delay?: number }) {
2727
initial={{ opacity: 0, y: 20 }}
2828
animate={{ opacity: 1, y: 0 }}
2929
transition={{ duration: 0.5, delay }}
30-
className="grid grid-cols-2 lg:grid-cols-3 gap-3 mb-10"
30+
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 mb-10"
3131
>
3232
{ALL_TOOLS.map((tool, i) => {
3333
const isActive = pathname === tool.to;

0 commit comments

Comments
 (0)