mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-03-26 17:51:54 +01:00
functional porting over user
This commit is contained in:
parent
0547fff1d5
commit
cb0a1e4fdc
@ -1,317 +0,0 @@
|
||||
"""testing
|
||||
|
||||
Revision ID: 5be3aa848ce8
|
||||
Revises: bceb1e139447
|
||||
Create Date: 2024-08-28 17:15:06.247199
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "5be3aa848ce8"
|
||||
down_revision = "bceb1e139447"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table(
|
||||
"chat_message__standard_answer",
|
||||
sa.Column("chat_message_id", sa.Integer(), nullable=False),
|
||||
sa.Column("standard_answer_id", sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(
|
||||
["chat_message_id"],
|
||||
["chat_message.id"],
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
["standard_answer_id"],
|
||||
["standard_answer.id"],
|
||||
),
|
||||
sa.PrimaryKeyConstraint("chat_message_id", "standard_answer_id"),
|
||||
)
|
||||
op.drop_table("kombu_queue")
|
||||
op.drop_index("ix_kombu_message_timestamp", table_name="kombu_message")
|
||||
op.drop_index("ix_kombu_message_timestamp_id", table_name="kombu_message")
|
||||
op.drop_index("ix_kombu_message_visible", table_name="kombu_message")
|
||||
op.drop_table("kombu_message")
|
||||
op.create_foreign_key(None, "api_key", "user", ["user_id"], ["id"])
|
||||
op.create_foreign_key(None, "api_key", "user", ["owner_id"], ["id"])
|
||||
op.alter_column(
|
||||
"chat_folder",
|
||||
"display_priority",
|
||||
existing_type=sa.INTEGER(),
|
||||
nullable=True,
|
||||
)
|
||||
op.drop_constraint("chat_message_id_key", "chat_message", type_="unique")
|
||||
op.alter_column(
|
||||
"credential",
|
||||
"source",
|
||||
existing_type=sa.VARCHAR(length=100),
|
||||
nullable=False,
|
||||
)
|
||||
op.alter_column(
|
||||
"credential",
|
||||
"credential_json",
|
||||
existing_type=postgresql.BYTEA(),
|
||||
nullable=False,
|
||||
)
|
||||
op.drop_index(
|
||||
"ix_document_by_connector_credential_pair_pkey__connecto_27dc",
|
||||
table_name="document_by_connector_credential_pair",
|
||||
)
|
||||
op.alter_column(
|
||||
"document_set__user", "user_id", existing_type=sa.UUID(), nullable=True
|
||||
)
|
||||
op.add_column(
|
||||
"email_to_external_user_cache",
|
||||
sa.Column(
|
||||
"source_type",
|
||||
sa.Enum(
|
||||
"INGESTION_API",
|
||||
"SLACK",
|
||||
"WEB",
|
||||
"GOOGLE_DRIVE",
|
||||
"GMAIL",
|
||||
"REQUESTTRACKER",
|
||||
"GITHUB",
|
||||
"GITLAB",
|
||||
"GURU",
|
||||
"BOOKSTACK",
|
||||
"CONFLUENCE",
|
||||
"SLAB",
|
||||
"JIRA",
|
||||
"PRODUCTBOARD",
|
||||
"FILE",
|
||||
"NOTION",
|
||||
"ZULIP",
|
||||
"LINEAR",
|
||||
"HUBSPOT",
|
||||
"DOCUMENT360",
|
||||
"GONG",
|
||||
"GOOGLE_SITES",
|
||||
"ZENDESK",
|
||||
"LOOPIO",
|
||||
"DROPBOX",
|
||||
"SHAREPOINT",
|
||||
"TEAMS",
|
||||
"SALESFORCE",
|
||||
"DISCOURSE",
|
||||
"AXERO",
|
||||
"CLICKUP",
|
||||
"MEDIAWIKI",
|
||||
"WIKIPEDIA",
|
||||
"S3",
|
||||
"R2",
|
||||
"GOOGLE_CLOUD_STORAGE",
|
||||
"OCI_STORAGE",
|
||||
"NOT_APPLICABLE",
|
||||
name="documentsource",
|
||||
native_enum=False,
|
||||
),
|
||||
nullable=False,
|
||||
),
|
||||
)
|
||||
op.alter_column(
|
||||
"inputprompt__user",
|
||||
"user_id",
|
||||
existing_type=sa.INTEGER(),
|
||||
nullable=True,
|
||||
)
|
||||
op.alter_column(
|
||||
"llm_provider", "provider", existing_type=sa.VARCHAR(), nullable=False
|
||||
)
|
||||
op.alter_column("persona__user", "user_id", existing_type=sa.UUID(), nullable=True)
|
||||
op.alter_column(
|
||||
"saml",
|
||||
"expires_at",
|
||||
existing_type=postgresql.TIMESTAMP(timezone=True),
|
||||
nullable=False,
|
||||
)
|
||||
op.alter_column(
|
||||
"search_settings",
|
||||
"query_prefix",
|
||||
existing_type=sa.VARCHAR(),
|
||||
nullable=True,
|
||||
)
|
||||
op.alter_column(
|
||||
"search_settings",
|
||||
"passage_prefix",
|
||||
existing_type=sa.VARCHAR(),
|
||||
nullable=True,
|
||||
)
|
||||
op.alter_column(
|
||||
"search_settings", "status", existing_type=sa.VARCHAR(), nullable=False
|
||||
)
|
||||
op.create_index(
|
||||
"ix_embedding_model_future_unique",
|
||||
"search_settings",
|
||||
["status"],
|
||||
unique=True,
|
||||
postgresql_where=sa.text("status = 'FUTURE'"),
|
||||
)
|
||||
op.create_index(
|
||||
"ix_embedding_model_present_unique",
|
||||
"search_settings",
|
||||
["status"],
|
||||
unique=True,
|
||||
postgresql_where=sa.text("status = 'PRESENT'"),
|
||||
)
|
||||
op.drop_constraint("standard_answer_keyword_key", "standard_answer", type_="unique")
|
||||
op.create_index(
|
||||
"unique_keyword_active",
|
||||
"standard_answer",
|
||||
["keyword", "active"],
|
||||
unique=True,
|
||||
postgresql_where=sa.text("active = true"),
|
||||
)
|
||||
op.alter_column(
|
||||
"tool_call",
|
||||
"tool_result",
|
||||
existing_type=postgresql.JSONB(astext_type=sa.Text()),
|
||||
nullable=True,
|
||||
)
|
||||
op.alter_column(
|
||||
"user__user_group", "user_id", existing_type=sa.UUID(), nullable=True
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.alter_column(
|
||||
"user__user_group", "user_id", existing_type=sa.UUID(), nullable=False
|
||||
)
|
||||
op.alter_column(
|
||||
"tool_call",
|
||||
"tool_result",
|
||||
existing_type=postgresql.JSONB(astext_type=sa.Text()),
|
||||
nullable=False,
|
||||
)
|
||||
op.drop_index(
|
||||
"unique_keyword_active",
|
||||
table_name="standard_answer",
|
||||
postgresql_where=sa.text("active = true"),
|
||||
)
|
||||
op.create_unique_constraint(
|
||||
"standard_answer_keyword_key", "standard_answer", ["keyword"]
|
||||
)
|
||||
op.drop_index(
|
||||
"ix_embedding_model_present_unique",
|
||||
table_name="search_settings",
|
||||
postgresql_where=sa.text("status = 'PRESENT'"),
|
||||
)
|
||||
op.drop_index(
|
||||
"ix_embedding_model_future_unique",
|
||||
table_name="search_settings",
|
||||
postgresql_where=sa.text("status = 'FUTURE'"),
|
||||
)
|
||||
op.alter_column(
|
||||
"search_settings", "status", existing_type=sa.VARCHAR(), nullable=True
|
||||
)
|
||||
op.alter_column(
|
||||
"search_settings",
|
||||
"passage_prefix",
|
||||
existing_type=sa.VARCHAR(),
|
||||
nullable=False,
|
||||
)
|
||||
op.alter_column(
|
||||
"search_settings",
|
||||
"query_prefix",
|
||||
existing_type=sa.VARCHAR(),
|
||||
nullable=False,
|
||||
)
|
||||
op.alter_column(
|
||||
"saml",
|
||||
"expires_at",
|
||||
existing_type=postgresql.TIMESTAMP(timezone=True),
|
||||
nullable=True,
|
||||
)
|
||||
op.alter_column("persona__user", "user_id", existing_type=sa.UUID(), nullable=False)
|
||||
op.alter_column(
|
||||
"llm_provider", "provider", existing_type=sa.VARCHAR(), nullable=True
|
||||
)
|
||||
op.alter_column(
|
||||
"inputprompt__user",
|
||||
"user_id",
|
||||
existing_type=sa.INTEGER(),
|
||||
nullable=False,
|
||||
)
|
||||
op.drop_column("email_to_external_user_cache", "source_type")
|
||||
op.alter_column(
|
||||
"document_set__user",
|
||||
"user_id",
|
||||
existing_type=sa.UUID(),
|
||||
nullable=False,
|
||||
)
|
||||
op.create_index(
|
||||
"ix_document_by_connector_credential_pair_pkey__connecto_27dc",
|
||||
"document_by_connector_credential_pair",
|
||||
["connector_id", "credential_id"],
|
||||
unique=False,
|
||||
)
|
||||
op.alter_column(
|
||||
"credential",
|
||||
"credential_json",
|
||||
existing_type=postgresql.BYTEA(),
|
||||
nullable=True,
|
||||
)
|
||||
op.alter_column(
|
||||
"credential",
|
||||
"source",
|
||||
existing_type=sa.VARCHAR(length=100),
|
||||
nullable=True,
|
||||
)
|
||||
op.create_unique_constraint("chat_message_id_key", "chat_message", ["id"])
|
||||
op.alter_column(
|
||||
"chat_folder",
|
||||
"display_priority",
|
||||
existing_type=sa.INTEGER(),
|
||||
nullable=False,
|
||||
)
|
||||
op.drop_constraint(None, "api_key", type_="foreignkey")
|
||||
op.drop_constraint(None, "api_key", type_="foreignkey")
|
||||
op.create_table(
|
||||
"kombu_message",
|
||||
sa.Column("id", sa.INTEGER(), autoincrement=False, nullable=False),
|
||||
sa.Column("visible", sa.BOOLEAN(), autoincrement=False, nullable=True),
|
||||
sa.Column(
|
||||
"timestamp",
|
||||
postgresql.TIMESTAMP(),
|
||||
autoincrement=False,
|
||||
nullable=True,
|
||||
),
|
||||
sa.Column("payload", sa.TEXT(), autoincrement=False, nullable=False),
|
||||
sa.Column("version", sa.SMALLINT(), autoincrement=False, nullable=False),
|
||||
sa.Column("queue_id", sa.INTEGER(), autoincrement=False, nullable=True),
|
||||
sa.ForeignKeyConstraint(
|
||||
["queue_id"], ["kombu_queue.id"], name="FK_kombu_message_queue"
|
||||
),
|
||||
sa.PrimaryKeyConstraint("id", name="kombu_message_pkey"),
|
||||
)
|
||||
op.create_index(
|
||||
"ix_kombu_message_visible", "kombu_message", ["visible"], unique=False
|
||||
)
|
||||
op.create_index(
|
||||
"ix_kombu_message_timestamp_id",
|
||||
"kombu_message",
|
||||
["timestamp", "id"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
"ix_kombu_message_timestamp",
|
||||
"kombu_message",
|
||||
["timestamp"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_table(
|
||||
"kombu_queue",
|
||||
sa.Column("id", sa.INTEGER(), autoincrement=False, nullable=False),
|
||||
sa.Column("name", sa.VARCHAR(length=200), autoincrement=False, nullable=True),
|
||||
sa.PrimaryKeyConstraint("id", name="kombu_queue_pkey"),
|
||||
sa.UniqueConstraint("name", name="kombu_queue_name_key"),
|
||||
)
|
||||
op.drop_table("chat_message__standard_answer")
|
||||
# ### end Alembic commands ###
|
@ -0,0 +1,24 @@
|
||||
"""add tenant id to user model
|
||||
|
||||
Revision ID: b25c363470f3
|
||||
Revises: 1f60f60c3401
|
||||
Create Date: 2024-08-29 17:03:20.794120
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "b25c363470f3"
|
||||
down_revision = "1f60f60c3401"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.add_column("user", sa.Column("tenant_id", sa.Text(), nullable=True))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column("user", "tenant_id")
|
@ -276,6 +276,7 @@ class UserManager(UUIDIDMixin, BaseUserManager[User, uuid.UUID]):
|
||||
) -> models.UP:
|
||||
verify_email_is_invited(user_create.email)
|
||||
verify_email_domain(user_create.email)
|
||||
print("CReATING")
|
||||
if hasattr(user_create, "role"):
|
||||
user_count = await get_user_count()
|
||||
if user_count == 0 or user_create.email in get_default_admin_user_emails():
|
||||
@ -360,7 +361,7 @@ async def sso_authenticate(
|
||||
) -> models.UP:
|
||||
user = await self.get_by_email(email)
|
||||
if not user:
|
||||
user_create = UserCreate(UserRole.BASIC)
|
||||
user_create = UserCreate(role=UserRole.BASIC)
|
||||
user = await self.create(user_create)
|
||||
|
||||
# Update user with tenant information if needed
|
||||
|
@ -239,7 +239,6 @@ def _datetime_from_string(datetime_string: str) -> datetime:
|
||||
else:
|
||||
# If not in UTC, translate it
|
||||
datetime_object = datetime_object.astimezone(timezone.utc)
|
||||
|
||||
return datetime_object
|
||||
|
||||
|
||||
|
@ -128,10 +128,11 @@ class User(SQLAlchemyBaseUserTableUUID, Base):
|
||||
oidc_expiry: Mapped[datetime.datetime] = mapped_column(
|
||||
TIMESTAMPAware(timezone=True), nullable=True
|
||||
)
|
||||
tenant_id: Mapped[str] = mapped_column(Text, nullable=True)
|
||||
|
||||
default_model: Mapped[str] = mapped_column(Text, nullable=True)
|
||||
# organized in typical structured fashion
|
||||
# formatted as `displayName__provider__modelName`
|
||||
default_model: Mapped[str] = mapped_column(Text, nullable=True)
|
||||
|
||||
# relationships
|
||||
credentials: Mapped[list["Credential"]] = relationship(
|
||||
|
@ -59,16 +59,13 @@ async def sso_callback(
|
||||
print("SSO callback reached")
|
||||
|
||||
payload = verify_sso_token(sso_token)
|
||||
print("hi")
|
||||
|
||||
user = await get_or_create_user(
|
||||
payload["email"], payload["user_id"], payload["tenant_id"]
|
||||
)
|
||||
print(user)
|
||||
|
||||
session_token = await create_user_session(user, strategy)
|
||||
print("Session creation attempt completed")
|
||||
logger.info(
|
||||
f"Session token created: {session_token[:10]}..."
|
||||
) # Log first 10 chars for security
|
||||
logger.info(f"Session token created: {session_token[:10]}...")
|
||||
logger.info(f"User email: {user.email}")
|
||||
logger.info(f"User ID: {user.id}")
|
||||
logger.info(f"User role: {user.role}")
|
||||
@ -86,30 +83,6 @@ async def sso_callback(
|
||||
return response
|
||||
|
||||
|
||||
# @basic_router.post("/auth/sso-callback")
|
||||
# async def sso_callback(
|
||||
# user = Depends(current_user),
|
||||
# token: str = Depends(oauth2_scheme),
|
||||
# strategy: Strategy = Depends(get_database_strategy),
|
||||
# user_manager: UserManager = Depends(get_user_manager),
|
||||
# ):
|
||||
# print('SSO callback reached')
|
||||
|
||||
# payload = verify_sso_token(token)
|
||||
# user = await get_or_create_user(payload["email"], payload["user_id"], payload["tenant_id"])
|
||||
# session_token = await create_user_session(user, strategy)
|
||||
|
||||
# response = RedirectResponse(url="/")
|
||||
# response.set_cookie(
|
||||
# key="session",
|
||||
# value=session_token,
|
||||
# httponly=True,
|
||||
# max_age=SESSION_EXPIRE_TIME_SECONDS,
|
||||
# secure=WEB_DOMAIN.startswith("https"),
|
||||
# )
|
||||
# return response
|
||||
|
||||
|
||||
@admin_router.put("")
|
||||
def put_settings(
|
||||
settings: Settings, _: User | None = Depends(current_admin_user)
|
||||
|
@ -2,11 +2,7 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { Card, Text } from "@tremor/react";
|
||||
import { Spinner } from "@/components/Spinner";
|
||||
import { SpinnerBall } from "@phosphor-icons/react/dist/ssr";
|
||||
import LogoType from "@/components/header/LogoType";
|
||||
import { Logo } from "@/components/Logo";
|
||||
import { HeaderTitle } from "@/components/header/HeaderTitle";
|
||||
|
||||
export default function SSOCallback() {
|
||||
const router = useRouter();
|
||||
@ -39,7 +35,7 @@ export default function SSOCallback() {
|
||||
setTimeout(() => {
|
||||
setAuthStatus("Redirecting to dashboard...");
|
||||
setTimeout(() => {
|
||||
router.push("/admin/plan");
|
||||
router.replace("/admin/plan");
|
||||
}, 1000);
|
||||
}, 1000);
|
||||
} else {
|
||||
@ -78,9 +74,8 @@ export default function SSOCallback() {
|
||||
) : (
|
||||
<div className="space-y-6 flex flex-col">
|
||||
<div className="flex mx-auto">
|
||||
<Logo height={80} width={80} />
|
||||
<Logo height={200} width={200} />
|
||||
</div>
|
||||
<SpinnerBall size="large" className="mx-auto text-neutral-600" />
|
||||
<Text className="text-2xl font-semibold text-text-900">
|
||||
{authStatus}
|
||||
</Text>
|
||||
|
@ -1,14 +1,18 @@
|
||||
"use client";
|
||||
|
||||
import { BillingPlanType } from "@/app/admin/settings/interfaces";
|
||||
import { useContext, useState } from "react";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { SettingsContext } from "@/components/settings/SettingsProvider";
|
||||
import { Button, Divider, Text, Card } from "@tremor/react";
|
||||
import { StripeCheckoutButton } from "./StripeCheckoutButton";
|
||||
import { CheckmarkIcon, XIcon } from "@/components/icons/icons";
|
||||
import { FiAward, FiDollarSign, FiStar } from "react-icons/fi";
|
||||
import { FiAward, FiDollarSign, FiHelpCircle, FiStar } from "react-icons/fi";
|
||||
import Cookies from "js-cookie";
|
||||
import { Modal } from "@/components/Modal";
|
||||
import { Logo } from "@/components/Logo";
|
||||
import Link from "next/link";
|
||||
|
||||
export function BillingSettings() {
|
||||
export function BillingSettings({ newUser }: { newUser: boolean }) {
|
||||
const settings = useContext(SettingsContext);
|
||||
const cloudSettings = settings?.cloudSettings;
|
||||
|
||||
@ -53,6 +57,7 @@ export function BillingSettings() {
|
||||
const [newSeats, setNewSeats] = useState(seats);
|
||||
const [newPlan, setNewPlan] = useState(currentPlan);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [isNewUserOpen, setIsNewUserOpen] = useState(true);
|
||||
|
||||
function getBillingPlanIcon(planType: BillingPlanType) {
|
||||
switch (planType) {
|
||||
@ -67,11 +72,49 @@ export function BillingSettings() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleCloseModal = () => {
|
||||
setIsNewUserOpen(false);
|
||||
Cookies.set("new_auth_user", "false");
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl mr-auto space-y-8 p-6">
|
||||
{newUser && isNewUserOpen && (
|
||||
<Modal
|
||||
onOutsideClick={handleCloseModal}
|
||||
className="max-w-lg w-full p-8 bg-bg-50 rounded-lg shadow-xl"
|
||||
>
|
||||
<>
|
||||
<h2 className="text-3xl font-extrabold text-text-900 mb-6 text-center">
|
||||
Welcome to Danswer!
|
||||
</h2>
|
||||
<div className="text-center mb-8">
|
||||
<Logo className="mx-auto mb-4" height={150} width={150} />
|
||||
<p className="text-lg text-text-700 leading-relaxed">
|
||||
We're thrilled to have you on board! Here, you can manage your
|
||||
billing settings and explore your plan details.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex justify-center">
|
||||
<Button
|
||||
onClick={handleCloseModal}
|
||||
className="px-8 py-3 bg-blue-600 text-white text-lg font-semibold rounded-full hover:bg-blue-700 transition duration-300 ease-in-out focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50"
|
||||
>
|
||||
Let's Get Started
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => window.open("mailto:support@danswer.ai")}
|
||||
className="border-0 hover:underline ml-4 px-4 py-2 bg-gray-200 w-fit text-text-700 text-sm font-medium rounded-full hover:bg-gray-300 transition duration-300 ease-in-out focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-opacity-50 flex items-center"
|
||||
>
|
||||
Questions?
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
</Modal>
|
||||
)}
|
||||
<Card className="bg-white shadow-lg rounded-lg overflow-hidden">
|
||||
<div className="px-8 py-6">
|
||||
<h2 className="text-3xl font-bold text-gray-800 mb-6 flex items-center">
|
||||
<h2 className="text-3xl font-bold text-text-800 mb-6 flex items-center">
|
||||
Your Plan
|
||||
<svg
|
||||
className="w-8 h-8 ml-2 text-blue-600"
|
||||
@ -90,9 +133,9 @@ export function BillingSettings() {
|
||||
</h2>
|
||||
<div className="space-y-6">
|
||||
<div className="flex justify-between items-center">
|
||||
<p className="text-lg text-gray-600 flex items-center">
|
||||
<p className="text-lg text-text-600 flex items-center">
|
||||
<svg
|
||||
className="w-5 h-5 mr-2 text-gray-500"
|
||||
className="w-5 h-5 mr-2 text-text-500"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
@ -112,9 +155,9 @@ export function BillingSettings() {
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center">
|
||||
<p className="text-lg text-gray-600 flex items-center">
|
||||
<p className="text-lg text-text-600 flex items-center">
|
||||
<svg
|
||||
className="w-5 h-5 mr-2 text-gray-500"
|
||||
className="w-5 h-5 mr-2 text-text-500"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
@ -137,7 +180,7 @@ export function BillingSettings() {
|
||||
<Divider />
|
||||
|
||||
<div className="mt-6 relative">
|
||||
<label className="block text-lg font-medium text-gray-700 mb-2 flex items-center">
|
||||
<label className="block text-lg font-medium text-text-700 mb-2 flex items-center">
|
||||
New Tier:
|
||||
</label>
|
||||
<div
|
||||
@ -149,7 +192,7 @@ export function BillingSettings() {
|
||||
<span className="ml-2 capitalize">{newPlan}</span>
|
||||
</span>
|
||||
<svg
|
||||
className="w-5 h-5 text-gray-400"
|
||||
className="w-5 h-5 text-text-400"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
@ -185,7 +228,7 @@ export function BillingSettings() {
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-6">
|
||||
<label className="block text-lg font-medium text-gray-700 mb-2 flex items-center">
|
||||
<label className="block text-lg font-medium text-text-700 mb-2 flex items-center">
|
||||
New Number of Seats:
|
||||
</label>
|
||||
{newPlan === BillingPlanType.FREE ? (
|
||||
@ -219,7 +262,7 @@ export function BillingSettings() {
|
||||
|
||||
<Card className="bg-white shadow-lg rounded-lg overflow-hidden">
|
||||
<div className="px-6 py-4">
|
||||
<h2 className="text-3xl font-bold text-gray-800 mb-4">Features</h2>
|
||||
<h2 className="text-3xl font-bold text-text-800 mb-4">Features</h2>
|
||||
<ul className="space-y-3">
|
||||
{features.map((feature, index) => (
|
||||
<li key={index} className="flex items-center text-lg">
|
||||
@ -232,7 +275,7 @@ export function BillingSettings() {
|
||||
</span>
|
||||
<span
|
||||
className={
|
||||
feature.included ? "text-gray-800" : "text-gray-500"
|
||||
feature.included ? "text-text-800" : "text-text-500"
|
||||
}
|
||||
>
|
||||
{feature.name}
|
||||
@ -245,10 +288,10 @@ export function BillingSettings() {
|
||||
{currentPlan !== BillingPlanType.FREE && (
|
||||
<Card className="bg-white shadow-lg rounded-lg overflow-hidden">
|
||||
<div className="px-8 py-6">
|
||||
<h2 className="text-3xl font-bold text-gray-800 mb-4">
|
||||
<h2 className="text-3xl font-bold text-text-800 mb-4">
|
||||
Tenant Deletion
|
||||
</h2>
|
||||
<p className="text-gray-600 mb-6">
|
||||
<p className="text-text-600 mb-6">
|
||||
Permanently delete your tenant and all associated data.
|
||||
</p>
|
||||
<div
|
||||
|
@ -1,8 +1,12 @@
|
||||
import { BillingSettings } from "./BillingSettings";
|
||||
import { AdminPageTitle } from "@/components/admin/Title";
|
||||
import { CreditCardIcon } from "@/components/icons/icons";
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export default async function Whitelabeling() {
|
||||
const newUser =
|
||||
cookies().get("new_auth_user")?.value.toLocaleLowerCase() === "true";
|
||||
|
||||
return (
|
||||
<div className="mx-auto container">
|
||||
<AdminPageTitle
|
||||
@ -10,7 +14,7 @@ export default async function Whitelabeling() {
|
||||
icon={<CreditCardIcon size={32} className="my-auto" />}
|
||||
/>
|
||||
|
||||
<BillingSettings />
|
||||
<BillingSettings newUser={newUser} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user