Merge remote-tracking branch 'origin/dev' into dropdownButton_component

This commit is contained in:
Lucas Oliveira 2023-08-31 10:43:28 -03:00
commit d2eb87d44b
11 changed files with 174 additions and 65 deletions

View file

@ -7,8 +7,17 @@ import { alertContext } from "../../contexts/alertContext";
import { AuthContext } from "../../contexts/authContext";
import { darkContext } from "../../contexts/darkContext";
import { TabsContext } from "../../contexts/tabsContext";
import { gradients } from "../../utils/styleUtils";
import IconComponent from "../genericIconComponent";
import { Button } from "../ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "../ui/dropdown-menu";
import { Separator } from "../ui/separator";
import MenuBar from "./components/menuBar";
@ -17,7 +26,7 @@ export default function Header(): JSX.Element {
const { dark, setDark } = useContext(darkContext);
const { notificationCenter } = useContext(alertContext);
const location = useLocation();
const { logout, autoLogin, isAdmin } = useContext(AuthContext);
const { logout, autoLogin, isAdmin, userData } = useContext(AuthContext);
const { stars } = useContext(darkContext);
const navigate = useNavigate();
@ -31,40 +40,6 @@ export default function Header(): JSX.Element {
{flows.findIndex((f) => tabId === f.id) !== -1 && tabId !== "" && (
<MenuBar flows={flows} tabId={tabId} />
)}
{!autoLogin && location.pathname !== `/flow/${tabId}` && (
<a
onClick={() => {
logout();
navigate("/login");
}}
className="mx-5 cursor-pointer text-sm font-medium text-muted-foreground transition-colors hover:text-primary"
>
Sign out
</a>
)}
{location.pathname === "/admin" && (
<a
onClick={() => {
navigate("/");
}}
className="cursor-pointer text-sm font-medium text-muted-foreground transition-colors hover:text-primary"
>
Home
</a>
)}
{isAdmin &&
!autoLogin &&
location.pathname !== "/admin" &&
location.pathname !== `/flow/${tabId}` && (
<a
className="cursor-pointer text-sm font-medium text-muted-foreground transition-colors hover:text-primary"
onClick={() => navigate("/admin")}
>
Admin page
</a>
)}
</div>
<div className="round-button-div">
<Link to="/">
@ -156,6 +131,40 @@ export default function Header(): JSX.Element {
/>
</button>
)}
{!autoLogin && (
<>
<Separator orientation="vertical" />
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button
className={
"h-7 w-7 rounded-full focus-visible:outline-0 " +
gradients[
parseInt(userData?.id ?? "", 10) % gradients.length
]
}
/>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuSeparator />
{isAdmin && (
<DropdownMenuItem onClick={() => navigate("/admin")}>
Admin Page
</DropdownMenuItem>
)}
<DropdownMenuItem
onClick={() => {
logout();
navigate("/login");
}}
>
Sign Out
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</>
)}
</div>
</div>
</div>

View file

@ -30,6 +30,7 @@ export default function InputComponent({
{isForm ? (
<Form.Control asChild>
<Input
type={password && !pwdVisible ? "password" : "text"}
value={value}
disabled={disabled}
required={required}
@ -53,6 +54,7 @@ export default function InputComponent({
</Form.Control>
) : (
<Input
type={password && !pwdVisible ? "password" : "text"}
value={value}
disabled={disabled}
required={required}
@ -76,6 +78,8 @@ export default function InputComponent({
)}
{password && (
<button
type="button"
tabIndex={-1}
className={classNames(
editNode
? "input-component-true-button"

View file

@ -0,0 +1,16 @@
import { Skeleton } from "../ui/skeleton";
export const SkeletonCardComponent = (): JSX.Element => {
return (
<div className="skeleton-card">
<div className="skeleton-card-wrapper">
<Skeleton className="h-8 w-8 rounded-full" />
<Skeleton className="h-4 w-[120px]" />
</div>
<div className="skeleton-card-text">
<Skeleton className="h-3 w-[250px]" />
<Skeleton className="h-3 w-[200px]" />
</div>
</div>
);
};

View file

@ -0,0 +1,15 @@
import { cn } from "../../utils/utils"
function Skeleton({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn("animate-pulse rounded-md bg-border", className)}
{...props}
/>
)
}
export { Skeleton }

View file

@ -39,6 +39,7 @@ const TabsContextInitialValue: TabsContextType = {
save: () => {},
tabId: "",
setTabId: (index: string) => {},
isLoading: true,
flows: [],
removeFlow: (id: string) => {},
addFlow: async (flowData?: any) => "",
@ -72,10 +73,12 @@ export const TabsContext = createContext<TabsContextType>(
export function TabsProvider({ children }: { children: ReactNode }) {
const { setErrorData, setNoticeData, setSuccessData } =
useContext(alertContext);
const { getAuthentication } = useContext(AuthContext);
const { getAuthentication, isAuthenticated } = useContext(AuthContext);
const [tabId, setTabId] = useState("");
const [isLoading, setIsLoading] = useState(true);
const [flows, setFlows] = useState<Array<FlowType>>([]);
const [id, setId] = useState(uid());
const { templates, reactFlowInstance } = useContext(typesContext);
@ -86,6 +89,12 @@ export function TabsProvider({ children }: { children: ReactNode }) {
const [tabsState, setTabsState] = useState<TabsState>({});
const [getTweak, setTweak] = useState<tweakType>([]);
useEffect(() => {
if (!isAuthenticated) {
hardReset();
}
}, [isAuthenticated]);
const newNodeId = useRef(uid());
function incrementNodeId() {
newNodeId.current = uid();
@ -116,11 +125,13 @@ export function TabsProvider({ children }: { children: ReactNode }) {
}
function refreshFlows() {
setIsLoading(true);
getTabsDataFromDB().then((DbData) => {
if (DbData && Object.keys(templates).length > 0) {
try {
processDBData(DbData);
updateStateWithDbData(DbData);
setIsLoading(false);
} catch (e) {}
}
});
@ -229,6 +240,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
setTabId("");
setFlows([]);
setIsLoading(true);
setId(uid());
}
@ -641,6 +653,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
paste,
getTweak,
setTweak,
isLoading,
}}
>
{children}

View file

@ -3,13 +3,21 @@ import { Link, useNavigate } from "react-router-dom";
import { CardComponent } from "../../components/cardComponent";
import IconComponent from "../../components/genericIconComponent";
import Header from "../../components/headerComponent";
import { SkeletonCardComponent } from "../../components/skeletonCardComponent";
import { Button } from "../../components/ui/button";
import { USER_PROJECTS_HEADER } from "../../constants/constants";
import { TabsContext } from "../../contexts/tabsContext";
import DropdownButton from "../../components/DropdownButtonComponent";
export default function HomePage(): JSX.Element {
const { flows, setTabId, downloadFlows, uploadFlows, addFlow, removeFlow, uploadFlow } =
useContext(TabsContext);
const {
flows,
setTabId,
downloadFlows,
uploadFlows,
addFlow,
removeFlow, uploadFlow,
isLoading,
} = useContext(TabsContext);
const dropdownOptions = [{name: "Import from JSON", onBtnClick: () => uploadFlow(true)}]
// Set a null id
@ -18,6 +26,10 @@ export default function HomePage(): JSX.Element {
}, []);
const navigate = useNavigate();
useEffect(() => {
console.log(isLoading);
}, [isLoading]);
// Personal flows display
return (
<>
@ -62,31 +74,40 @@ export default function HomePage(): JSX.Element {
Manage your personal projects. Download or upload your collection.
</span>
<div className="main-page-flows-display">
{flows.map((flow, idx) => (
<CardComponent
key={idx}
flow={flow}
id={flow.id}
button={
<Link to={"/flow/" + flow.id}>
<Button
variant="outline"
size="sm"
className="whitespace-nowrap "
>
<IconComponent
name="ExternalLink"
className="main-page-nav-button"
/>
Edit Flow
</Button>
</Link>
}
onDelete={() => {
removeFlow(flow.id);
}}
/>
))}
{isLoading && flows.length == 0 ? (
<>
<SkeletonCardComponent />
<SkeletonCardComponent />
<SkeletonCardComponent />
<SkeletonCardComponent />
</>
) : (
flows.map((flow, idx) => (
<CardComponent
key={idx}
flow={flow}
id={flow.id}
button={
<Link to={"/flow/" + flow.id}>
<Button
variant="outline"
size="sm"
className="whitespace-nowrap "
>
<IconComponent
name="ExternalLink"
className="main-page-nav-button"
/>
Edit Flow
</Button>
</Link>
}
onDelete={() => {
removeFlow(flow.id);
}}
/>
))
)}
</div>
</div>
</>

View file

@ -90,6 +90,7 @@ export default function LoginPage(): JSX.Element {
<Form.Control asChild>
<Input
type="username"
onChange={({ target: { value } }) => {
handleInput({ target: { name: "username", value } });
}}
@ -130,12 +131,12 @@ export default function LoginPage(): JSX.Element {
</div>
<div className="w-full">
<Form.Submit asChild>
<Button className="mr-3 mt-6 w-full">Sign in</Button>
<Button className="mr-3 mt-6 w-full" type="submit">Sign in</Button>
</Form.Submit>
</div>
<div className="w-full">
<Link to="/signup">
<Button className="w-full" variant="outline">
<Button className="w-full" variant="outline" type="button">
Don't have an account?&nbsp;<b>Sign Up</b>
</Button>
</Link>

View file

@ -84,6 +84,7 @@ export default function SignUp(): JSX.Element {
<Form.Control asChild>
<Input
type="username"
onChange={({ target: { value } }) => {
handleInput({ target: { name: "username", value } });
}}
@ -157,6 +158,7 @@ export default function SignUp(): JSX.Element {
<div className="w-full">
<Form.Submit asChild>
<Button
type="submit"
className="mr-3 mt-6 w-full"
onClick={() => {
handleSignup();

View file

@ -126,6 +126,18 @@
@apply form-input block w-full truncate rounded-md border-border bg-background px-3 text-left shadow-sm placeholder:text-muted-foreground focus:border-ring focus:placeholder-transparent focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 sm:text-sm;
}
.skeleton-card {
@apply bg-background h-48 p-4 border rounded-lg flex flex-col gap-6;
}
.skeleton-card-wrapper {
@apply flex items-center space-x-4;
}
.skeleton-card-text {
@apply flex flex-col gap-3;
}
/* The same as primary-input but no-truncate */
.textarea-primary {
@apply form-input block w-full rounded-md border-border bg-background px-3 text-left shadow-sm placeholder:text-muted-foreground focus:border-ring focus:placeholder-transparent focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 sm:text-sm;

View file

@ -36,3 +36,18 @@ pre {
.gradient-start {
animation: gradient-motion-start 4s infinite forwards;
}
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
textarea:-webkit-autofill,
textarea:-webkit-autofill:hover,
textarea:-webkit-autofill:focus,
select:-webkit-autofill,
select:-webkit-autofill:hover,
select:-webkit-autofill:focus {
-webkit-text-fill-color: black;
-webkit-box-shadow: 0 0 0px 1000px #fff6d0 inset;
box-shadow: 0 0 0px 1000px #fff6d0 inset;
color: black;
}

View file

@ -5,6 +5,7 @@ export type TabsContextType = {
saveFlow: (flow: FlowType) => Promise<void>;
save: () => void;
tabId: string;
isLoading: boolean;
setTabId: (index: string) => void;
flows: Array<FlowType>;
removeFlow: (id: string) => void;