diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 9def360..d29df9d 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -13,12 +13,15 @@ "@hey-api/openapi-ts": "^0.99.0", "@supabase/supabase-js": "^2.110.8", "@tailwindcss/vite": "^4.2.2", + "@tanstack/react-table": "^8.21.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "date-fns": "^4.4.0", "lucide-react": "^1.8.0", "radix-ui": "^1.4.3", "react": "^19.2.4", "react-circle-flags": "^0.0.29", + "react-day-picker": "^10.0.1", "react-dom": "^19.2.4", "react-router-dom": "7.18.2", "shadcn": "^4.2.0", @@ -522,6 +525,12 @@ } } }, + "node_modules/@date-fns/tz": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@date-fns/tz/-/tz-1.5.0.tgz", + "integrity": "sha512-lwYN/vDPeNRULcepoE/LO2Pgx+7/RV+S9ARfbc9lr2DtGkOD7pAiruHvbR1RX3Qyf6ja47EWJDMsNK5vK08DJg==", + "license": "MIT" + }, "node_modules/@dotenvx/dotenvx": { "version": "1.75.1", "resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.75.1.tgz", @@ -3601,6 +3610,39 @@ "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, + "node_modules/@tanstack/react-table": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.3.tgz", + "integrity": "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==", + "license": "MIT", + "dependencies": { + "@tanstack/table-core": "8.21.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/@tanstack/table-core": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.21.3.tgz", + "integrity": "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@ts-morph/common": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.27.0.tgz", @@ -3612,6 +3654,42 @@ "path-browserify": "^1.0.1" } }, + "node_modules/@ts-morph/common/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@ts-morph/common/node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@ts-morph/common/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@tybys/wasm-util": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", @@ -3859,6 +3937,42 @@ "typescript": ">=4.8.4 <6.1.0" } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { "version": "7.8.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", @@ -4645,6 +4759,16 @@ "devOptional": true, "license": "MIT" }, + "node_modules/date-fns": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.4.0.tgz", + "integrity": "sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debounce-fn": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-4.0.0.tgz", @@ -5363,9 +5487,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", - "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", "funding": [ { "type": "github", @@ -7510,6 +7634,32 @@ "react": "^16.0.0 || 17.x || 18.x || 19.x" } }, + "node_modules/react-day-picker": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-10.0.1.tgz", + "integrity": "sha512-eNh6BlwcYInWaJtRv18mXQ06Ys/H6rdTZAnTaSdOYJuTpwP1JMCHNd1FDRadA+gbeinq+psdULN5Xnowy9mV8w==", + "license": "MIT", + "dependencies": { + "@date-fns/tz": "^1.4.1", + "date-fns": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/gpbl" + }, + "peerDependencies": { + "@types/react": ">=16.8.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-dom": { "version": "19.2.7", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", diff --git a/frontend/package.json b/frontend/package.json index 5e8f0a5..bcf7111 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,12 +19,15 @@ "@hey-api/openapi-ts": "^0.99.0", "@supabase/supabase-js": "^2.110.8", "@tailwindcss/vite": "^4.2.2", + "@tanstack/react-table": "^8.21.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "date-fns": "^4.4.0", "lucide-react": "^1.8.0", "radix-ui": "^1.4.3", "react": "^19.2.4", "react-circle-flags": "^0.0.29", + "react-day-picker": "^10.0.1", "react-dom": "^19.2.4", "react-router-dom": "7.18.2", "shadcn": "^4.2.0", diff --git a/frontend/public/Images/auth/SignupSideImage.png b/frontend/public/Images/auth/SignupSideImage.png new file mode 100644 index 0000000..fcf1543 Binary files /dev/null and b/frontend/public/Images/auth/SignupSideImage.png differ diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 37c3cff..40e66a3 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -4,9 +4,31 @@ import { useAuth } from '@/context/AuthContext'; import SessionPage from './pages/Session'; import LoginPage from './pages/Login_page'; import Home from './pages/Home'; -import CreateCommittee from './pages/CreateCommittee'; -import UserDash from './pages/UserDashboard'; import Pricing from './pages/Info Pages/Pricing'; +import OurTeam from './pages/Info Pages/OurTeam'; +import ContactUs from './pages/Info Pages/Contact-us'; +import SignupPage from './pages/Signup'; +import UserDash from './pages/UserDashboard'; +import DashHome from './components/userDashboard/dash-home.tsx'; +import CreateCommittee from './pages/CreateCommittee'; +import BasicInfo from './components/userDashboard/conferenceMenus/about/conference-basic-info.tsx'; + + +import ConferenceOverview from './components/userDashboard/conferenceMenus/conference-overview'; +import Enrollment from './components/userDashboard/conferenceMenus/participants/enrollment'; +import ParticipantListAllocation from './components/userDashboard/conferenceMenus/participants/list-allocation'; +import PresenceCertificates from './components/userDashboard/conferenceMenus/participants/presence-certificates'; +import ConferenceSchedule from './components/userDashboard/conferenceMenus/about/conference-schedule'; +import TeamStructure from './components/userDashboard/conferenceMenus/team/team-structure'; +import TeamAllocate from './components/userDashboard/conferenceMenus/team/team-alocate'; +import CommitteeManagement from './components/userDashboard/conferenceMenus/committee-managemant'; +import ConferenceDocs from './components/userDashboard/conferenceMenus/about/conference-docs'; +import ManagePermsRoles from './components/userDashboard/conferenceMenus/team/manage-perms-roles.tsx'; +import CommitteeSessions from './components/userDashboard/committeeMenus/committee-sessions.tsx'; +import CommitteeDocs from './components/userDashboard/committeeMenus/committee-docs.tsx'; +import CommitteeInfo from './components/userDashboard/committeeMenus/committee-info.tsx'; + + function RequireAuth({ children }: { children: ReactNode }) { const { loading, token } = useAuth(); @@ -28,10 +50,29 @@ function App() { element={} /> } /> - } /> + } /> + } /> } /> + } /> + }> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> - } /> + } /> diff --git a/frontend/src/components/auth/login-form.tsx b/frontend/src/components/auth/login-form.tsx index 98e7e99..88b4e12 100644 --- a/frontend/src/components/auth/login-form.tsx +++ b/frontend/src/components/auth/login-form.tsx @@ -10,6 +10,7 @@ import { FieldSeparator, } from "@/components/ui/field" import { Input } from "@/components/ui/input" +import { Link } from "react-router-dom" import { supabase } from "@/lib/supabaseClient" export function LoginForm({ @@ -114,9 +115,9 @@ export function LoginForm({ Don't have an account?{" "} - + Sign up - + diff --git a/frontend/src/components/auth/signup-form.tsx b/frontend/src/components/auth/signup-form.tsx new file mode 100644 index 0000000..d7078a0 --- /dev/null +++ b/frontend/src/components/auth/signup-form.tsx @@ -0,0 +1,93 @@ +import { cn } from "@/lib/utils" +import { Button } from "@/components/ui/button" +import { + Field, + FieldDescription, + FieldGroup, + FieldLabel, + FieldSeparator, +} from "@/components/ui/field" +import { Input } from "@/components/ui/input" +import { Link } from "react-router-dom" + +export function SignupForm({ + className, + ...props +}: React.ComponentProps<"form">) { + return ( +
+ +
+

Create your account

+

+ Fill in the form below to create your account +

+
+ + Full Name + + + + Email + + + We'll use this to contact you. We will not share your email + with anyone else. + + + + Password + + + Must be at least 8 characters long. + + + + Confirm Password + + Please confirm your password. + + + + + Or continue with + + + + Already have an account? Sign in + + +
+
+ ) +} diff --git a/frontend/src/components/homepage/footer.tsx b/frontend/src/components/homepage/footer.tsx index e9fb3db..2a0de37 100644 --- a/frontend/src/components/homepage/footer.tsx +++ b/frontend/src/components/homepage/footer.tsx @@ -1,28 +1,46 @@ - - import { Link } from "react-router-dom" +import { Button } from "@/components/ui/button" import { Separator } from "@/components/ui/separator" const footerLinkGroups = [ { title: "Sobre Nós", - items: ["Equipe", "Nossa História", "Imprensa"], + items: [ + { label: "Equipe", to: "/our-team" }, + { label: "Nossa História", to: "/our-team" }, + { label: "Imprensa", to: "/contact-us" }, + ], }, { title: "O Produto", - items: ["Documentação", "Preços", "Changelog", "Repositório GitHub"], + items: [ + { label: "Documentação", to: "/dashboard" }, + { label: "Preços", to: "/pricing" }, + { label: "Changelog", to: "/dashboard" }, + { label: "Repositório GitHub", href: "https://github.com" }, + ], }, { title: "Contato", - items: ["Duvidas", "Suporte", "Seja nosso parceiro"], + items: [ + { label: "Duvidas", to: "/contact-us" }, + { label: "Suporte", to: "/contact-us" }, + { label: "Seja nosso parceiro", to: "/contact-us" }, + ], }, { title: "Redes Sociais", - items: ["Instagram", "Twitter", "LinkedIn", "TikTok", "YouTube"], + items: [ + { label: "Instagram", href: "https://instagram.com" }, + { label: "Twitter", href: "https://x.com" }, + { label: "LinkedIn", href: "https://linkedin.com" }, + { label: "TikTok", href: "https://tiktok.com" }, + { label: "YouTube", href: "https://youtube.com" }, + ], }, ] -const placeholderLinkClassName = "cursor-pointer transition hover:underline" +const LinkClassName = "cursor-pointer transition hover:underline" export default function Footer() { @@ -38,14 +56,18 @@ export default function Footer() {

{group.title}

    {group.items.map((item) => ( -
  • - event.preventDefault()} - className={placeholderLinkClassName} - > - {item} - +
  • +
  • ))}
@@ -55,9 +77,21 @@ export default function Footer() {
    -
  • event.preventDefault()} className={placeholderLinkClassName}>Política de Privacidade
  • -
  • event.preventDefault()} className={placeholderLinkClassName}>Termos de Serviço
  • -
  • event.preventDefault()} className={placeholderLinkClassName}>Cookies
  • +
  • + +
  • +
  • + +
  • +
  • + +
diff --git a/frontend/src/components/homepage/navbar.tsx b/frontend/src/components/homepage/navbar.tsx index f2b3831..3e06498 100644 --- a/frontend/src/components/homepage/navbar.tsx +++ b/frontend/src/components/homepage/navbar.tsx @@ -78,6 +78,9 @@ export default function Navbar() { Conheça os termos de uso do WebMun e nossa política de privacidade. + + Tem dúvidas ou sugestões? Entre em contato conosco! + @@ -85,7 +88,7 @@ export default function Navbar() { Sobre
    - + Conheça a equipe por trás do WebMun! @@ -105,12 +108,14 @@ export default function Navbar() {
    - + - -
    diff --git a/frontend/src/components/ui/calendar.tsx b/frontend/src/components/ui/calendar.tsx new file mode 100644 index 0000000..ead1c58 --- /dev/null +++ b/frontend/src/components/ui/calendar.tsx @@ -0,0 +1,220 @@ +import * as React from "react" +import { + DayPicker, + getDefaultClassNames, + type DayButton, + type Locale, +} from "react-day-picker" + +import { cn } from "@/lib/utils" +import { Button, buttonVariants } from "@/components/ui/button" +import { ChevronLeftIcon, ChevronRightIcon, ChevronDownIcon } from "lucide-react" + +function Calendar({ + className, + classNames, + showOutsideDays = true, + captionLayout = "label", + buttonVariant = "ghost", + locale, + formatters, + components, + ...props +}: React.ComponentProps & { + buttonVariant?: React.ComponentProps["variant"] +}) { + const defaultClassNames = getDefaultClassNames() + + return ( + svg]:rotate-180`, + String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`, + className + )} + captionLayout={captionLayout} + locale={locale} + formatters={{ + formatMonthDropdown: (date) => + date.toLocaleString(locale?.code, { month: "short" }), + ...formatters, + }} + classNames={{ + root: cn("w-fit", defaultClassNames.root), + months: cn( + "relative flex flex-col gap-4 md:flex-row", + defaultClassNames.months + ), + month: cn("flex w-full flex-col gap-4", defaultClassNames.month), + nav: cn( + "absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1", + defaultClassNames.nav + ), + button_previous: cn( + buttonVariants({ variant: buttonVariant }), + "size-(--cell-size) p-0 select-none aria-disabled:opacity-50", + defaultClassNames.button_previous + ), + button_next: cn( + buttonVariants({ variant: buttonVariant }), + "size-(--cell-size) p-0 select-none aria-disabled:opacity-50", + defaultClassNames.button_next + ), + month_caption: cn( + "flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)", + defaultClassNames.month_caption + ), + dropdowns: cn( + "flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium", + defaultClassNames.dropdowns + ), + dropdown_root: cn( + "relative rounded-(--cell-radius)", + defaultClassNames.dropdown_root + ), + dropdown: cn( + "absolute inset-0 bg-popover opacity-0", + defaultClassNames.dropdown + ), + caption_label: cn( + "font-medium select-none", + captionLayout === "label" + ? "text-sm" + : "flex items-center gap-1 rounded-(--cell-radius) text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground", + defaultClassNames.caption_label + ), + month_grid: cn("w-full border-collapse", defaultClassNames.month_grid), + weekdays: cn("flex", defaultClassNames.weekdays), + weekday: cn( + "flex-1 rounded-(--cell-radius) text-[0.8rem] font-normal text-muted-foreground select-none", + defaultClassNames.weekday + ), + week: cn("mt-2 flex w-full", defaultClassNames.week), + week_number_header: cn( + "w-(--cell-size) select-none", + defaultClassNames.week_number_header + ), + week_number: cn( + "text-[0.8rem] text-muted-foreground select-none", + defaultClassNames.week_number + ), + day: cn( + "group/day relative aspect-square h-full w-full rounded-(--cell-radius) p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-r-(--cell-radius)", + props.showWeekNumber + ? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-(--cell-radius)" + : "[&:first-child[data-selected=true]_button]:rounded-l-(--cell-radius)", + defaultClassNames.day + ), + range_start: cn( + "relative isolate z-0 rounded-l-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:right-0 after:w-4 after:bg-muted", + defaultClassNames.range_start + ), + range_middle: cn("rounded-none", defaultClassNames.range_middle), + range_end: cn( + "relative isolate z-0 rounded-r-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:left-0 after:w-4 after:bg-muted", + defaultClassNames.range_end + ), + today: cn( + "rounded-(--cell-radius) bg-muted text-foreground data-[selected=true]:rounded-none", + defaultClassNames.today + ), + outside: cn( + "text-muted-foreground aria-selected:text-muted-foreground", + defaultClassNames.outside + ), + disabled: cn( + "text-muted-foreground opacity-50", + defaultClassNames.disabled + ), + hidden: cn("invisible", defaultClassNames.hidden), + ...classNames, + }} + components={{ + Root: ({ className, rootRef, ...props }) => { + return ( +
    + ) + }, + Chevron: ({ className, orientation, ...props }) => { + if (orientation === "left") { + return ( + + ) + } + + if (orientation === "right") { + return ( + + ) + } + + return ( + + ) + }, + DayButton: ({ ...props }) => ( + + ), + WeekNumber: ({ children, ...props }) => { + return ( + +
    + {children} +
    + + ) + }, + ...components, + }} + {...props} + /> + ) +} + +function CalendarDayButton({ + className, + day, + modifiers, + locale, + ...props +}: React.ComponentProps & { locale?: Partial }) { + const defaultClassNames = getDefaultClassNames() + + const ref = React.useRef(null) + React.useEffect(() => { + if (modifiers.focused) ref.current?.focus() + }, [modifiers.focused]) + + return ( +