fix: some fix responsive

This commit is contained in:
charlesgauthereau
2026-01-29 23:46:04 +01:00
parent 30b9fc7765
commit 966edfa85a
5 changed files with 66 additions and 55 deletions
@@ -34,17 +34,10 @@ export default async function RoutePage(props: PageParams<{ slug: string }>) {
const storageChannels = await getOrganizationStorageChannels(organization.id) const storageChannels = await getOrganizationStorageChannels(organization.id)
const permissions = computeOrganizationPermissions(activeMember); const permissions = computeOrganizationPermissions(activeMember);
// Fetch users for the form
const users = await db.query.user.findMany({ const users = await db.query.user.findMany({
where: (fields) => isNull(fields.deletedAt) where: (fields) => isNull(fields.deletedAt)
}); });
// Re-fetch organization with members to match type expectations if needed,
// although getOrganization returns OrganizationWithMembers usually, let's verify or cast.
// getOrganization returns Organization type from database schema, which includes relations if defined in auth lib.
// However, OrganizationForm expects OrganizationWithMembers.
// Let's ensure we have members.
const organizationWithMembers = await db.query.organization.findFirst({ const organizationWithMembers = await db.query.organization.findFirst({
where: eq(drizzleDb.schemas.organization.id, organization.id), where: eq(drizzleDb.schemas.organization.id, organization.id),
with: { with: {
@@ -58,7 +51,6 @@ export default async function RoutePage(props: PageParams<{ slug: string }>) {
if (!organizationWithMembers) notFound(); if (!organizationWithMembers) notFound();
return ( return (
<Page> <Page>
<PageHeader> <PageHeader>
@@ -73,11 +65,7 @@ export default async function RoutePage(props: PageParams<{ slug: string }>) {
organization={organizationWithMembers} organization={organizationWithMembers}
users={users} users={users}
currentUser={user} currentUser={user}
> />
<Button variant="outline">
<GearIcon className="w-7 h-7"/>
</Button>
</EditOrganizationDialog>
)} )}
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@@ -7,6 +7,7 @@ import {Setting} from "@/db/schema/01_setting";
import {SettingsEmailSection} from "@/components/wrappers/dashboard/admin/settings/email/settings-email-section"; import {SettingsEmailSection} from "@/components/wrappers/dashboard/admin/settings/email/settings-email-section";
import {SettingsStorageSection} from "@/components/wrappers/dashboard/admin/settings/storage/settings-storage-section"; import {SettingsStorageSection} from "@/components/wrappers/dashboard/admin/settings/storage/settings-storage-section";
import {StorageChannelWith} from "@/db/schema/12_storage-channel"; import {StorageChannelWith} from "@/db/schema/12_storage-channel";
import {MailboxIcon, Save} from "lucide-react";
export type SettingsTabsProps = { export type SettingsTabsProps = {
settings: Setting settings: Setting
@@ -30,29 +31,44 @@ export const SettingsTabs = ({settings, storageChannels}: SettingsTabsProps) =>
}; };
const tabs = [
{
name: 'System Email',
value: 'email',
icon: MailboxIcon,
content: (
<SettingsEmailSection settings={settings}/>
)
},
{
name: 'Default Storage',
value: 'storage',
icon: Save,
content: (
<SettingsStorageSection storageChannels={storageChannels} settings={settings}/>
)
}
]
return ( return (
<div className="h-full mt-3"> <div className="h-full mt-3">
<Tabs className="h-full" value={tab} onValueChange={handleChangeTab}> <Tabs className="h-full gap-4" value={tab} onValueChange={handleChangeTab}>
<TabsList className='bg-background rounded-none border-b p-0 min-w-48'> <TabsList>
<TabsTrigger {tabs.map(({icon: Icon, name, value}) => (
value="email" <TabsTrigger key={value} value={value} className='flex items-center gap-1 px-2.5 sm:px-3'>
className='bg-background data-[state=active]:border-primary dark:data-[state=active]:border-primary h-full rounded-none border-0 border-b-2 border-transparent data-[state=active]:shadow-none' <Icon/>
> {name}
Email
</TabsTrigger>
<TabsTrigger
value="storage"
className='bg-background data-[state=active]:border-primary dark:data-[state=active]:border-primary h-full rounded-none border-0 border-b-2 border-transparent data-[state=active]:shadow-none'
>
Default storage
</TabsTrigger> </TabsTrigger>
))}
</TabsList> </TabsList>
<TabsContent className="h-full" value="email">
<SettingsEmailSection settings={settings}/> {tabs.map(tab => (
</TabsContent> <TabsContent key={tab.value} value={tab.value} className="h-full">
<TabsContent className="h-full" value="storage"> {tab.content}
<SettingsStorageSection storageChannels={storageChannels} settings={settings}/>
</TabsContent> </TabsContent>
))}
</Tabs> </Tabs>
</div> </div>
@@ -64,15 +64,15 @@ export const SettingsStorageSection = ({settings, storageChannels}: SettingsStor
await mutation.mutateAsync(values); await mutation.mutateAsync(values);
}} }}
> >
<div className="flex items-center gap-3"> <div className="flex flex-wrap items-center gap-3">
<FormField <FormField
control={form.control} control={form.control}
name="storageChannelId" name="storageChannelId"
render={({field}) => ( render={({ field }) => (
<FormItem className="flex items-center justify-center"> <FormItem className="flex-grow min-w-[200px] sm:flex-grow-0 sm:w-64">
<Select value={field.value} onValueChange={field.onChange}> <Select value={field.value} onValueChange={field.onChange}>
<SelectTrigger className="w-90 h-full mb-0"> <SelectTrigger className="w-full h-full mb-0">
<SelectValue placeholder="Select a default storage channel"/> <SelectValue placeholder="Select a default storage channel" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
{storageChannels.map((channel) => ( {storageChannels.map((channel) => (
@@ -80,8 +80,7 @@ export const SettingsStorageSection = ({settings, storageChannels}: SettingsStor
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{getChannelIcon(channel.provider)} {getChannelIcon(channel.provider)}
<span className="font-medium">{channel.name}</span> <span className="font-medium">{channel.name}</span>
<span <span className="text-[9px] uppercase bg-secondary px-1.5 py-0.5 rounded">
className="text-[9px] uppercase bg-secondary px-1.5 py-0.5 rounded">
{channel.provider} {channel.provider}
</span> </span>
</div> </div>
@@ -92,10 +91,11 @@ export const SettingsStorageSection = ({settings, storageChannels}: SettingsStor
</FormItem> </FormItem>
)} )}
/> />
<ButtonWithLoading type="submit"> <ButtonWithLoading className="flex-shrink-0 w-full sm:w-auto" type="submit">
Confirm Confirm
</ButtonWithLoading> </ButtonWithLoading>
</div> </div>
</Form> </Form>
</div> </div>
</div> </div>
@@ -8,38 +8,46 @@ import {
DialogTrigger, DialogTrigger,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import {OrganizationForm} from "@/features/organization/components/organization.form"; import {OrganizationForm} from "@/features/organization/components/organization.form";
import {useState} from "react"; import {ReactNode, useState} from "react";
import {Button, buttonVariants} from "@/components/ui/button"; import {Button, buttonVariants} from "@/components/ui/button";
import {GearIcon} from "@radix-ui/react-icons"; import {GearIcon} from "@radix-ui/react-icons";
import {OrganizationWithMembers} from "@/db/schema/03_organization"; import {OrganizationWithMembers} from "@/db/schema/03_organization";
import {User} from "@/db/schema/02_user"; import {User} from "@/db/schema/02_user";
import {User as BetterAuthUser} from "better-auth"; import {User as BetterAuthUser} from "better-auth";
import {useRouter} from "next/navigation";
type EditOrganizationDialogProps = { type EditOrganizationDialogProps = {
children?: React.ReactNode;
organization: OrganizationWithMembers; organization: OrganizationWithMembers;
users: User[]; users: User[];
currentUser: BetterAuthUser; currentUser: BetterAuthUser;
}; };
export const EditOrganizationDialog = ({children, organization, users, currentUser}: EditOrganizationDialogProps) => { export const EditOrganizationDialog = ({
organization,
users,
currentUser,
}: EditOrganizationDialogProps) => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const router = useRouter();
return ( return (
<Dialog open={open} onOpenChange={setOpen}> <Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild> <DialogTrigger asChild>
{children ? children : ( <div className={buttonVariants({variant: "outline", className: "cursor-pointer"})}>
<Button variant="outline"> <GearIcon className="w-7 h-7"/>
<GearIcon className="w-4 h-4 mr-2"/> Edit </div>
</Button>
)}
</DialogTrigger> </DialogTrigger>
<DialogContent> <DialogContent
onOpenAutoFocus={(e) => e.preventDefault()}
>
<DialogHeader> <DialogHeader>
<DialogTitle>Edit {organization.name}</DialogTitle> <DialogTitle>Edit {organization.name}</DialogTitle>
</DialogHeader> </DialogHeader>
<OrganizationForm <OrganizationForm
onSuccess={() => setOpen(false)} onSuccess={() => {
setOpen(false)
router.refresh()
}}
defaultValues={organization} defaultValues={organization}
users={users} users={users}
currentUser={currentUser} currentUser={currentUser}
@@ -18,7 +18,6 @@ import {GearIcon} from "@radix-ui/react-icons";
import {EmptyStatePlaceholder} from "@/components/wrappers/common/empty-state-placeholder"; import {EmptyStatePlaceholder} from "@/components/wrappers/common/empty-state-placeholder";
type ProjectDialogProps = { type ProjectDialogProps = {
children?: ReactNode;
databases: DatabaseWith[]; databases: DatabaseWith[];
organization: Organization; organization: Organization;
project?: ProjectWith; project?: ProjectWith;