fix: centralizar OnboardingModal em /organizations e evitar reabertura (#15)
O modal de onboarding era disparado tanto na LoginPage quanto no AppShell com navegação conflitante, fazendo ele fechar e reabrir ao escolher uma opção. Agora o login sem org redireciona para /organizations, o AppShell redireciona usuários sem org para lá, e o modal é exibido uma única vez pela OrganizationsPage. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
2fdb375462
commit
5c53379568
3 changed files with 22 additions and 24 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Layout,
|
Layout,
|
||||||
ListTodo,
|
ListTodo,
|
||||||
|
|
@ -18,9 +18,8 @@ import {
|
||||||
Users,
|
Users,
|
||||||
PlusCircle,
|
PlusCircle,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { NavLink, Outlet, Navigate, Link } from "react-router-dom";
|
import { NavLink, Outlet, Navigate, Link, useLocation } from "react-router-dom";
|
||||||
import { useAuth } from "../contexts/AuthContext";
|
import { useAuth } from "../contexts/AuthContext";
|
||||||
import { OnboardingModal } from "./OnboardingModal";
|
|
||||||
|
|
||||||
import { cn } from "../lib/utils";
|
import { cn } from "../lib/utils";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
|
|
@ -44,7 +43,7 @@ const dropdownItemClassName = ({ isActive }: { isActive: boolean }) =>
|
||||||
export function AppShell() {
|
export function AppShell() {
|
||||||
const { user, isAuthenticated, isLoading, logout, activeOrg, setActiveOrg } =
|
const { user, isAuthenticated, isLoading, logout, activeOrg, setActiveOrg } =
|
||||||
useAuth();
|
useAuth();
|
||||||
const [showOrgModal, setShowOrgModal] = useState(false);
|
const location = useLocation();
|
||||||
const [showOrgSwitcher, setShowOrgSwitcher] = useState(false);
|
const [showOrgSwitcher, setShowOrgSwitcher] = useState(false);
|
||||||
const [showTasksDropdown, setShowTasksDropdown] = useState(false);
|
const [showTasksDropdown, setShowTasksDropdown] = useState(false);
|
||||||
const [showTeamDropdown, setShowTeamDropdown] = useState(false);
|
const [showTeamDropdown, setShowTeamDropdown] = useState(false);
|
||||||
|
|
@ -53,12 +52,6 @@ export function AppShell() {
|
||||||
const isAdmin =
|
const isAdmin =
|
||||||
activeOrg?.roles.includes("OWNER") || activeOrg?.roles.includes("ADMIN");
|
activeOrg?.roles.includes("OWNER") || activeOrg?.roles.includes("ADMIN");
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (isAuthenticated && user && user.organizations.length === 0) {
|
|
||||||
setShowOrgModal(true);
|
|
||||||
}
|
|
||||||
}, [isAuthenticated, user]);
|
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="flex min-h-screen items-center justify-center bg-app-bg text-brand">
|
<div className="flex min-h-screen items-center justify-center bg-app-bg text-brand">
|
||||||
|
|
@ -71,6 +64,15 @@ export function AppShell() {
|
||||||
return <Navigate to="/login" replace />;
|
return <Navigate to="/login" replace />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
isAuthenticated &&
|
||||||
|
user &&
|
||||||
|
user.organizations.length === 0 &&
|
||||||
|
location.pathname !== "/organizations"
|
||||||
|
) {
|
||||||
|
return <Navigate to="/organizations" replace />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex min-h-screen flex-col bg-app-bg font-sans text-text-main">
|
<div className="flex min-h-screen flex-col bg-app-bg font-sans text-text-main">
|
||||||
{/* Top Navigation */}
|
{/* Top Navigation */}
|
||||||
|
|
@ -622,10 +624,6 @@ export function AppShell() {
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</footer>
|
</footer>
|
||||||
<OnboardingModal
|
|
||||||
isOpen={showOrgModal}
|
|
||||||
onClose={() => setShowOrgModal(false)}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,11 @@ import { useNavigate, Link } from 'react-router-dom'
|
||||||
import { motion } from 'framer-motion'
|
import { motion } from 'framer-motion'
|
||||||
import { Mail, Lock, LogIn, Layout } from 'lucide-react'
|
import { Mail, Lock, LogIn, Layout } from 'lucide-react'
|
||||||
import { useAuth } from '../contexts/AuthContext'
|
import { useAuth } from '../contexts/AuthContext'
|
||||||
import { OnboardingModal } from '../components/OnboardingModal'
|
|
||||||
|
|
||||||
export const LoginPage: React.FC = () => {
|
export const LoginPage: React.FC = () => {
|
||||||
const [email, setEmail] = useState('')
|
const [email, setEmail] = useState('')
|
||||||
const [password, setPassword] = useState('')
|
const [password, setPassword] = useState('')
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
const [showOnboarding, setShowOnboarding] = useState(false)
|
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const { login } = useAuth()
|
const { login } = useAuth()
|
||||||
|
|
||||||
|
|
@ -20,7 +18,7 @@ export const LoginPage: React.FC = () => {
|
||||||
try {
|
try {
|
||||||
const response = await login(email, password)
|
const response = await login(email, password)
|
||||||
if (response.organizations.length === 0) {
|
if (response.organizations.length === 0) {
|
||||||
setShowOnboarding(true)
|
navigate('/organizations')
|
||||||
} else {
|
} else {
|
||||||
navigate('/')
|
navigate('/')
|
||||||
}
|
}
|
||||||
|
|
@ -113,13 +111,6 @@ export const LoginPage: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
<OnboardingModal
|
|
||||||
isOpen={showOnboarding}
|
|
||||||
onClose={() => {
|
|
||||||
setShowOnboarding(false)
|
|
||||||
navigate('/')
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,13 @@ import { Link } from 'react-router-dom'
|
||||||
import { useAuth } from '../contexts/AuthContext'
|
import { useAuth } from '../contexts/AuthContext'
|
||||||
import { cn } from '../lib/utils'
|
import { cn } from '../lib/utils'
|
||||||
import { organizationService } from '../services/organizationService'
|
import { organizationService } from '../services/organizationService'
|
||||||
|
import { OnboardingModal } from '../components/OnboardingModal'
|
||||||
|
|
||||||
export function OrganizationsPage() {
|
export function OrganizationsPage() {
|
||||||
const { user, activeOrg, setActiveOrg, refreshUser } = useAuth()
|
const { user, activeOrg, setActiveOrg, refreshUser } = useAuth()
|
||||||
|
const [showOnboarding, setShowOnboarding] = useState(
|
||||||
|
() => (user?.organizations.length ?? 0) === 0,
|
||||||
|
)
|
||||||
const [showCreateModal, setShowCreateModal] = useState(false)
|
const [showCreateModal, setShowCreateModal] = useState(false)
|
||||||
const [newOrgName, setNewOrgName] = useState('')
|
const [newOrgName, setNewOrgName] = useState('')
|
||||||
const [isCreating, setIsCreating] = useState(false)
|
const [isCreating, setIsCreating] = useState(false)
|
||||||
|
|
@ -250,6 +254,11 @@ export function OrganizationsPage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<OnboardingModal
|
||||||
|
isOpen={showOnboarding}
|
||||||
|
onClose={() => setShowOnboarding(false)}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Create Organization Modal */}
|
{/* Create Organization Modal */}
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{showCreateModal && (
|
{showCreateModal && (
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue