infra: add linting and formatting for js projects (#230)
* wip * wip * wip * format * wip(mobile): lint and format * cleanup * nits * nits * idiomatic react * nit * format all root files
This commit was merged in pull request #230.
This commit is contained in:
@@ -1,26 +1,26 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
|
||||
import { ArrowLeft, CreditCard, Mail, Shield, Users, X } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Muted } from "@/components/ui/typography";
|
||||
import { WindowControls } from "@/components/window-controls";
|
||||
import { useNetworks } from "@/hooks/use-networks";
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
import { ArrowLeft, CreditCard, Mail, Shield, Users, X } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { Muted } from '@/components/ui/typography';
|
||||
import { WindowControls } from '@/components/window-controls';
|
||||
import { useNetworks } from '@/hooks/use-networks';
|
||||
import {
|
||||
useNetworkInvitations,
|
||||
useInviteMembers,
|
||||
useRevokeInvitation,
|
||||
useRemoveMember,
|
||||
} from "@/hooks/use-member-management";
|
||||
import { useAuthStore } from "@/stores/auth-store";
|
||||
import { BillingSection } from "@/features/network-billing";
|
||||
import { ConfirmDestructiveOverlay } from "@/components/confirm-destructive-overlay";
|
||||
import type { Human } from "@/api/types";
|
||||
} from '@/hooks/use-member-management';
|
||||
import { useAuthStore } from '@/stores/auth-store';
|
||||
import { BillingSection } from '@/features/network-billing';
|
||||
import { ConfirmDestructiveOverlay } from '@/components/confirm-destructive-overlay';
|
||||
import type { Human } from '@/api/types';
|
||||
|
||||
function MemberRow({
|
||||
human,
|
||||
@@ -66,7 +66,7 @@ function MemberRow({
|
||||
}
|
||||
|
||||
function InviteForm({ networkId }: { networkId: string }) {
|
||||
const [email, setEmail] = useState("");
|
||||
const [email, setEmail] = useState('');
|
||||
const inviteMembers = useInviteMembers(networkId);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
@@ -77,7 +77,7 @@ function InviteForm({ networkId }: { networkId: string }) {
|
||||
inviteMembers.mutate([trimmed], {
|
||||
onSuccess: () => {
|
||||
toast.success(`Invitation sent to ${trimmed}`);
|
||||
setEmail("");
|
||||
setEmail('');
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -96,7 +96,7 @@ function InviteForm({ networkId }: { networkId: string }) {
|
||||
size="sm"
|
||||
disabled={!email.trim() || inviteMembers.isPending}
|
||||
>
|
||||
{inviteMembers.isPending ? "Sending..." : "Invite"}
|
||||
{inviteMembers.isPending ? 'Sending...' : 'Invite'}
|
||||
</Button>
|
||||
</form>
|
||||
);
|
||||
@@ -179,24 +179,30 @@ function Section({ children }: { children: React.ReactNode }) {
|
||||
export default function NetworkSettingsPage() {
|
||||
const navigate = useNavigate();
|
||||
const { networkId } = useParams<{ networkId: string }>();
|
||||
if (!networkId)
|
||||
throw new Error('NetworkSettingsPage requires a :networkId route param');
|
||||
const [searchParams] = useSearchParams();
|
||||
const { data: networks } = useNetworks();
|
||||
const network = networks?.find((n) => n.id === networkId);
|
||||
const { data: invitations, error: invitationsError } = useNetworkInvitations(networkId!);
|
||||
const { data: invitations, error: invitationsError } =
|
||||
useNetworkInvitations(networkId);
|
||||
const currentUser = useAuthStore((s) => s.user);
|
||||
const isAdmin = currentUser?.id === network?.admin_human.id;
|
||||
const [memberToRemove, setMemberToRemove] = useState<Human | null>(null);
|
||||
const removeMember = useRemoveMember(networkId!);
|
||||
const removeMember = useRemoveMember(networkId);
|
||||
|
||||
const billingRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (searchParams.get("section") === "billing") {
|
||||
billingRef.current?.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
if (searchParams.get('section') === 'billing') {
|
||||
billingRef.current?.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start',
|
||||
});
|
||||
}
|
||||
}, [searchParams]);
|
||||
|
||||
const networkName = network?.name ?? "Network";
|
||||
const networkName = network?.name ?? 'Network';
|
||||
const memberCount = network?.humans.length ?? 0;
|
||||
const pendingCount = invitations?.length ?? 0;
|
||||
const networkInitials = networkName.slice(0, 2).toUpperCase();
|
||||
@@ -227,8 +233,8 @@ export default function NetworkSettingsPage() {
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="truncate text-base font-semibold">{networkName}</p>
|
||||
<Muted className="text-xs">
|
||||
{memberCount} {memberCount === 1 ? "member" : "members"}
|
||||
{isAdmin ? " · You're an admin" : ""}
|
||||
{memberCount} {memberCount === 1 ? 'member' : 'members'}
|
||||
{isAdmin ? " · You're an admin" : ''}
|
||||
</Muted>
|
||||
</div>
|
||||
</div>
|
||||
@@ -254,7 +260,9 @@ export default function NetworkSettingsPage() {
|
||||
<MemberRow
|
||||
human={human}
|
||||
isAdmin={isRowAdmin}
|
||||
onRemove={canRemove ? () => setMemberToRemove(human) : undefined}
|
||||
onRemove={
|
||||
canRemove ? () => setMemberToRemove(human) : undefined
|
||||
}
|
||||
/>
|
||||
{index < network.humans.length - 1 && (
|
||||
<Separator className="mx-4" />
|
||||
@@ -279,7 +287,7 @@ export default function NetworkSettingsPage() {
|
||||
}
|
||||
/>
|
||||
<Separator />
|
||||
<InviteForm networkId={networkId!} />
|
||||
<InviteForm networkId={networkId} />
|
||||
{invitationsError && (
|
||||
<>
|
||||
<Separator />
|
||||
@@ -288,7 +296,7 @@ export default function NetworkSettingsPage() {
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
{pendingCount > 0 && (
|
||||
{invitations && invitations.length > 0 && (
|
||||
<>
|
||||
<Separator />
|
||||
<div className="px-4 pb-1 pt-3">
|
||||
@@ -296,13 +304,13 @@ export default function NetworkSettingsPage() {
|
||||
Pending
|
||||
</Muted>
|
||||
</div>
|
||||
{invitations!.map((inv, index) => (
|
||||
{invitations.map((inv, index) => (
|
||||
<div key={inv.email}>
|
||||
<PendingInvitationRow
|
||||
email={inv.email}
|
||||
networkId={networkId!}
|
||||
networkId={networkId}
|
||||
/>
|
||||
{index < invitations!.length - 1 && (
|
||||
{index < invitations.length - 1 && (
|
||||
<Separator className="mx-4" />
|
||||
)}
|
||||
</div>
|
||||
@@ -319,12 +327,12 @@ export default function NetworkSettingsPage() {
|
||||
title="Billing"
|
||||
description={
|
||||
isAdmin
|
||||
? "Manage your plan, seats, and payment."
|
||||
? 'Manage your plan, seats, and payment.'
|
||||
: "Your network's current plan and usage."
|
||||
}
|
||||
/>
|
||||
<Separator />
|
||||
<BillingSection networkId={networkId!} />
|
||||
<BillingSection networkId={networkId} />
|
||||
</Section>
|
||||
</div>
|
||||
|
||||
@@ -342,7 +350,8 @@ export default function NetworkSettingsPage() {
|
||||
</li>
|
||||
<li>Any content they posted stays in the network.</li>
|
||||
<li>
|
||||
If they're in a live huddle, they may remain until the call ends.
|
||||
If they're in a live huddle, they may remain until the call
|
||||
ends.
|
||||
</li>
|
||||
</ul>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user