diff --git a/.depcheckrc b/.depcheckrc new file mode 100644 index 0000000..1e44b72 --- /dev/null +++ b/.depcheckrc @@ -0,0 +1,2 @@ +ignores: ["eslint", "babel-*", "depcheck", "@types/node", "@types/react-dom", "autoprefixer", "postcss"] +skip-missing: false diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..26f5c15 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +.github diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml new file mode 100644 index 0000000..d023901 --- /dev/null +++ b/.github/workflows/check.yaml @@ -0,0 +1,35 @@ +name: Checks + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + run-checks: + name: Run checks + runs-on: ubuntu-latest + + steps: + - name: Check out Git repository + uses: actions/checkout@v2 + + - name: Set up Node.js + uses: actions/setup-node@v1 + with: + node-version: 20 + + - name: Install Node.js dependencies + run: yarn install --frozen-lockfile + + - name: Run linters + uses: wearerequired/lint-action@v2 + with: + eslint: true + prettier: true + + - name: Run dependency check + run: npx depcheck diff --git a/.prettierignore b/.prettierignore index 951d0ad..c1bcfde 100644 --- a/.prettierignore +++ b/.prettierignore @@ -10,3 +10,4 @@ node_modules .next build .contentlayer +.github diff --git a/README.md b/README.md index 3b13f7c..48a611f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@
- +
@@ -37,7 +37,7 @@ After setting up the required services, you need to set the corresponding enviro ```sh-session cp .env.example .env ``` -2. Open the `/apps/web/.env` file in a text editor and populate the values for the services mentioned above. +2. Open the `.env` file in a text editor and populate the values for the services mentioned above. ## Build diff --git a/app/(authenticated)/(app)/DesktopSidebar.tsx b/app/(authenticated)/(app)/DesktopSidebar.tsx index f5291ab..a5efc75 100644 --- a/app/(authenticated)/(app)/DesktopSidebar.tsx +++ b/app/(authenticated)/(app)/DesktopSidebar.tsx @@ -1,7 +1,14 @@ import { Logo } from "@/components/logo"; import { Button } from "@/components/ui/button"; import { ScrollArea } from "@/components/ui/scroll-area"; -import { BarChart, Database, FileKey, Filter, FormInput, Home } from "lucide-react"; +import { + BarChart, + Database, + FileKey, + Filter, + FormInput, + Home, +} from "lucide-react"; import { ChannelLink } from "./channelLink"; import { TeamSwitcher } from "./TeamSwitcher"; import Link from "next/link"; @@ -29,38 +36,64 @@ export const DesktopSidebar: React.FC = ({ navigation, channels }) => {
-

{/* Events */}

+

+ {/* Events */} +

- - - - -
-

Channels

+

+ Channels +

{channels diff --git a/app/(authenticated)/(app)/MobileSidebar.tsx b/app/(authenticated)/(app)/MobileSidebar.tsx index 980fa5d..1bb565a 100644 --- a/app/(authenticated)/(app)/MobileSidebar.tsx +++ b/app/(authenticated)/(app)/MobileSidebar.tsx @@ -49,38 +49,64 @@ export const MobileSidebar: React.FC = ({ channels }) => {
-

{/* Events */}

+

+ {/* Events */} +

- - - - -
-

Events

+

+ Events +

{channels.map((channel) => ( diff --git a/app/(authenticated)/(app)/TeamSwitcher.tsx b/app/(authenticated)/(app)/TeamSwitcher.tsx index d37641c..e53c749 100644 --- a/app/(authenticated)/(app)/TeamSwitcher.tsx +++ b/app/(authenticated)/(app)/TeamSwitcher.tsx @@ -12,7 +12,12 @@ import { useRouter } from "next/navigation"; import { useState } from "react"; import { Loading } from "@/components/loading"; -import { useAuth, useOrganization, useOrganizationList, useUser } from "@clerk/clerk-react"; +import { + useAuth, + useOrganization, + useOrganizationList, + useUser, +} from "@clerk/clerk-react"; import { Avatar, AvatarImage } from "@/components/ui/avatar"; import { AvatarFallback } from "@radix-ui/react-avatar"; @@ -51,10 +56,15 @@ export const TeamSwitcher: React.FC = (): JSX.Element => {
{user?.profileImageUrl ? ( - + ) : null} - {(currentOrg?.slug ?? user?.username ?? "").slice(0, 2).toUpperCase() ?? "P"} + {(currentOrg?.slug ?? user?.username ?? "") + .slice(0, 2) + .toUpperCase() ?? "P"} {currentOrg?.name ?? "Personal"} diff --git a/app/(authenticated)/(app)/overview/page.tsx b/app/(authenticated)/(app)/overview/page.tsx index 483f394..3e6674b 100644 --- a/app/(authenticated)/(app)/overview/page.tsx +++ b/app/(authenticated)/(app)/overview/page.tsx @@ -1,20 +1,17 @@ - import { cn } from "@/lib/utils"; -export default async function Page(_props: { - params: { tenantSlug: string }; -}) { +export default async function Page(_props: { params: { tenantSlug: string } }) { const stats: { label: string; value: string; }[] = [ { label: "Total Channels", - value: '0', + value: "0", }, { label: "Total Events (7 days)", - value: '0', + value: "0", }, ]; return ( @@ -47,7 +44,7 @@ export default async function Page(_props: { "lg:grid-cols-2": stats.length === 2, "lg:grid-cols-3": stats.length === 3, "lg:grid-cols-4": stats.length >= 4, - }, + } )} > {" "} @@ -55,11 +52,17 @@ export default async function Page(_props: {
-
{stat.label}
+
+ {stat.label} +
{/*
More details - - - +
diff --git a/app/(authenticated)/layout.tsx b/app/(authenticated)/layout.tsx index d972fce..e6eed60 100644 --- a/app/(authenticated)/layout.tsx +++ b/app/(authenticated)/layout.tsx @@ -1,11 +1,12 @@ import { Particles } from "@/components/landing/particles"; -import { ClerkProvider, SignIn, SignedIn, SignedOut } from "@clerk/nextjs/app-beta"; +import { + ClerkProvider, + SignIn, + SignedIn, + SignedOut, +} from "@clerk/nextjs/app-beta"; -export default function AppLayout({ - children, -}: { - children: React.ReactNode; -}) { +export default function AppLayout({ children }: { children: React.ReactNode }) { return ( {children} diff --git a/app/(landing)/layout.tsx b/app/(landing)/layout.tsx index b681a8a..614158d 100644 --- a/app/(landing)/layout.tsx +++ b/app/(landing)/layout.tsx @@ -42,7 +42,11 @@ export default function DefaultLayout({ className="text-gray-500 hover:text-gray-400" > Github - + ( - + {

Simplify your workflows

-

A consolidated ticket dashboard within 60 seconds.

+

+ A consolidated ticket dashboard within 60 seconds. +

{ { icon: Unplug, name: "Effortless Consolidation", - description: "Consolidate all tickets from multiple platforms and clients effortlessly", + description: + "Consolidate all tickets from multiple platforms and clients effortlessly", }, { icon: Eye, name: "Unparalleled Visibility", - description: "Gain complete control and visibility over your ticketing operations", + description: + "Gain complete control and visibility over your ticketing operations", }, { icon: Compass, name: "Intuitive Navigation", - description: "Seamlessly navigate and find tickets with smart filters and advanced search", + description: + "Seamlessly navigate and find tickets with smart filters and advanced search", }, { icon: Zap, name: "Enhanced Efficiency", - description: "Maximize productivity and resource allocation in ticket management", + description: + "Maximize productivity and resource allocation in ticket management", }, ]; return ( @@ -62,7 +66,9 @@ export const Features: React.FC = () => { Reduce Context Switching

- Empower your operations teams with by consolidating all ticket information in one place. Seamlessly filter, sort, and customize ticket views to meet their unique needs. + Empower your operations teams with by consolidating all ticket + information in one place. Seamlessly filter, sort, and + customize ticket views to meet their unique needs.

{features.map((feature) => ( diff --git a/components/landing/hero.tsx b/components/landing/hero.tsx index ac14a37..622ef58 100644 --- a/components/landing/hero.tsx +++ b/components/landing/hero.tsx @@ -32,9 +32,15 @@ export const Hero: React.FC = () => { className="pb-4 font-extrabold tracking-tight text-transparent text-6xl lg:text-8xl bg-clip-text bg-gradient-to-r from-zinc-200/60 via-zinc-200 to-zinc-200/60" data-aos="fade-down" > - One Dashboard, Countless Solutions + + One Dashboard, Countless Solutions + -

+

Tame ticket overload and keep your operation teams sane

= ({ const dx = (Math.random() - 0.5) * 0.2; const dy = (Math.random() - 0.5) * 0.2; const magnetism = 0.1 + Math.random() * 4; - return { x, y, translateX, translateY, size, alpha, targetAlpha, dx, dy, magnetism }; + return { + x, + y, + translateX, + translateY, + size, + alpha, + targetAlpha, + dx, + dy, + magnetism, + }; }; const rgb = hexToRgb(color); @@ -149,7 +160,12 @@ export const Particles: React.FC = ({ const clearContext = () => { if (context.current) { - context.current.clearRect(0, 0, canvasSize.current.w, canvasSize.current.h); + context.current.clearRect( + 0, + 0, + canvasSize.current.w, + canvasSize.current.h + ); } }; @@ -167,9 +183,10 @@ export const Particles: React.FC = ({ start1: number, end1: number, start2: number, - end2: number, + end2: number ): number => { - const remapped = ((value - start1) * (end2 - start2)) / (end1 - start1) + start2; + const remapped = + ((value - start1) * (end2 - start2)) / (end1 - start1) + start2; return remapped > 0 ? remapped : 0; }; @@ -184,7 +201,9 @@ export const Particles: React.FC = ({ canvasSize.current.h - circle.y - circle.translateY - circle.size, // distance from bottom edge ]; const closestEdge = edge.reduce((a, b) => Math.min(a, b)); - const remapClosestEdge = parseFloat(remapValue(closestEdge, 0, 20, 0, 1).toFixed(2)); + const remapClosestEdge = parseFloat( + remapValue(closestEdge, 0, 20, 0, 1).toFixed(2) + ); if (remapClosestEdge > 1) { circle.alpha += 0.02; if (circle.alpha > circle.targetAlpha) { @@ -196,9 +215,11 @@ export const Particles: React.FC = ({ circle.x += circle.dx + vx; circle.y += circle.dy + vy; circle.translateX += - (mouse.current.x / (staticity / circle.magnetism) - circle.translateX) / ease; + (mouse.current.x / (staticity / circle.magnetism) - circle.translateX) / + ease; circle.translateY += - (mouse.current.y / (staticity / circle.magnetism) - circle.translateY) / ease; + (mouse.current.y / (staticity / circle.magnetism) - circle.translateY) / + ease; // circle gets out of the canvas if ( circle.x < -circle.size || @@ -222,7 +243,7 @@ export const Particles: React.FC = ({ translateY: circle.translateY, alpha: circle.alpha, }, - true, + true ); } }); diff --git a/components/landing/utils/mouse-position.tsx b/components/landing/utils/mouse-position.tsx index 0d54fc7..b3f827d 100644 --- a/components/landing/utils/mouse-position.tsx +++ b/components/landing/utils/mouse-position.tsx @@ -6,7 +6,10 @@ interface MousePosition { } export default function useMousePosition(): MousePosition { - const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 }); + const [mousePosition, setMousePosition] = useState({ + x: 0, + y: 0, + }); useEffect(() => { const handleMouseMove = (event: MouseEvent) => { diff --git a/components/loading.tsx b/components/loading.tsx index 7e592a8..d86f385 100644 --- a/components/loading.tsx +++ b/components/loading.tsx @@ -14,13 +14,30 @@ export function Loading({ xmlns="http://www.w3.org/2000/svg" > - + - + - + ); diff --git a/components/logo.tsx b/components/logo.tsx index 03b5d24..92162ee 100644 --- a/components/logo.tsx +++ b/components/logo.tsx @@ -13,13 +13,12 @@ export const Logo: React.FC = ({ className }) => { stroke="current" strokeWidth="2" strokeLinecap="round" - strokeLinejoin="round"> - - - - + strokeLinejoin="round" + > + + + + ); }; - - diff --git a/components/mobile-nav.tsx b/components/mobile-nav.tsx index 0883aaa..8000e78 100644 --- a/components/mobile-nav.tsx +++ b/components/mobile-nav.tsx @@ -26,7 +26,8 @@ export function MobileNav() { variant="ghost" className="-ml-4 text-base hover:bg-transparent focus:ring-0 focus:ring-offset-0 md:hidden" > - Menu + {" "} + Menu = ({ title, description, actions }) => { +export const PageHeader: React.FC = ({ + title, + description, + actions, +}) => { return (

{title}

-

{description}

+

+ {description} +

    {(actions ?? []).map((action, i) => ( diff --git a/components/ui/avatar.tsx b/components/ui/avatar.tsx index 1d9ba9d..f5eba05 100644 --- a/components/ui/avatar.tsx +++ b/components/ui/avatar.tsx @@ -11,7 +11,10 @@ const Avatar = React.forwardRef< >(({ className, ...props }, ref) => ( )); @@ -37,7 +40,7 @@ const AvatarFallback = React.forwardRef< ref={ref} className={cn( "flex h-full w-full items-center justify-center rounded-full bg-zinc-100 dark:bg-zinc-700", - className, + className )} {...props} /> diff --git a/components/ui/button.tsx b/components/ui/button.tsx index ba96182..aa257ef 100644 --- a/components/ui/button.tsx +++ b/components/ui/button.tsx @@ -8,11 +8,14 @@ const buttonVariants = cva( { variants: { variant: { - default: "bg-zinc-900 text-white hover:bg-zinc-700 dark:bg-zinc-50 dark:text-zinc-900", - destructive: "bg-red-500 text-white hover:bg-red-600 dark:hover:bg-red-600", + default: + "bg-zinc-900 text-white hover:bg-zinc-700 dark:bg-zinc-50 dark:text-zinc-900", + destructive: + "bg-red-500 text-white hover:bg-red-600 dark:hover:bg-red-600", outline: "bg-transparent border border-zinc-200 hover:bg-zinc-100 dark:border-zinc-700 dark:text-zinc-100", - subtle: "bg-zinc-100 text-zinc-900 hover:bg-zinc-200 dark:bg-zinc-800 dark:text-zinc-100", + subtle: + "bg-zinc-100 text-zinc-900 hover:bg-zinc-200 dark:bg-zinc-800 dark:text-zinc-100", ghost: "bg-transparent hover:bg-zinc-100 dark:hover:bg-zinc-800 dark:text-zinc-100 dark:hover:text-zinc-100 data-[state=open]:bg-transparent dark:data-[state=open]:bg-transparent", link: "bg-transparent dark:bg-transparent underline-offset-4 hover:underline text-zinc-900 dark:text-zinc-100 hover:bg-transparent dark:hover:bg-transparent", @@ -28,7 +31,7 @@ const buttonVariants = cva( variant: "default", size: "default", }, - }, + } ); export interface ButtonProps @@ -38,9 +41,13 @@ export interface ButtonProps const Button = React.forwardRef( ({ className, variant, size, ...props }, ref) => { return ( -