From 05a512a9421854c0523bb401a6f5cf730c6dc9d4 Mon Sep 17 00:00:00 2001 From: devmc-ee Date: Sun, 15 Jun 2025 10:05:52 +0300 Subject: [PATCH 1/6] B2B-30: hide 'create team' button from not super_admins --- .env | 11 +++++++---- .env.development | 14 +++++++------- .env.example | 9 ++++++++- app/(marketing)/page.tsx | 4 ++-- app/(public)/register-company/page.tsx | 4 ++-- .../register-company/success/page.tsx | 5 +++-- components.json | 2 +- components/app-logo.tsx | 19 ++----------------- components/med-report-title.tsx | 5 +++-- lib/dev-mock-modules.ts | 2 +- next.config.mjs | 8 ++++---- package.json | 4 ++-- .../src/components/account-selector.tsx | 17 ++++++++++++++--- packages/ui/components.json | 2 +- styles/STYLE_GUIDE.md | 9 ++++++++- supabase/config.toml | 10 +++++----- 16 files changed, 70 insertions(+), 55 deletions(-) diff --git a/.env b/.env index 09a319e..164e333 100644 --- a/.env +++ b/.env @@ -33,9 +33,9 @@ NEXT_PUBLIC_LOCALES_PATH=apps/web/public/locales # FEATURE FLAGS NEXT_PUBLIC_ENABLE_THEME_TOGGLE=true NEXT_PUBLIC_ENABLE_PERSONAL_ACCOUNT_DELETION=true -NEXT_PUBLIC_ENABLE_PERSONAL_ACCOUNT_BILLING=true -NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_DELETION=true -NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_BILLING=true +NEXT_PUBLIC_ENABLE_PERSONAL_ACCOUNT_BILLING=false +NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_DELETION=false +NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_BILLING=false NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS=true NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_CREATION=true NEXT_PUBLIC_LANGUAGE_PRIORITY=application @@ -46,4 +46,7 @@ NEXT_TELEMETRY_DISABLED=1 LOGGER=pino -NEXT_PUBLIC_DEFAULT_LOCALE=et \ No newline at end of file +NEXT_PUBLIC_DEFAULT_LOCALE=et + +NEXT_PUBLIC_TEAM_NAVIGATION_STYLE=custom +NEXT_PUBLIC_USER_NAVIGATION_STYLE=custom \ No newline at end of file diff --git a/.env.development b/.env.development index 82a3969..c22cdb6 100644 --- a/.env.development +++ b/.env.development @@ -10,12 +10,6 @@ SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhY SUPABASE_DB_WEBHOOK_SECRET=WEBHOOKSECRET # EMAILS -EMAIL_SENDER="Makerkit " -EMAIL_PORT=54325 -EMAIL_HOST=localhost -EMAIL_TLS=false -EMAIL_USER=user -EMAIL_PASSWORD=password # CONTACT FORM CONTACT_EMAIL=test@makerkit.dev @@ -24,4 +18,10 @@ CONTACT_EMAIL=test@makerkit.dev NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY= # MAILER -MAILER_PROVIDER=nodemailer \ No newline at end of file +MAILER_PROVIDER=nodemailer +# EMAIL_SENDER= +# EMAIL_USER= # refer to your email provider's documentation +# EMAIL_PASSWORD= # refer to your email provider's documentation +# EMAIL_HOST= # refer to your email provider's documentation +# EMAIL_PORT= # or 465 for SSL +# EMAIL_TLS= # or false for SSL (see provider documentation) \ No newline at end of file diff --git a/.env.example b/.env.example index 3686882..46d3948 100644 --- a/.env.example +++ b/.env.example @@ -7,4 +7,11 @@ NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY=your-service-role-key MEDIPOST_URL=your-medipost-url MEDIPOST_USER=your-medipost-user MEDIPOST_PASSWORD=your-medipost-password -MEDIPOST_RECIPIENT=your-medipost-recipient \ No newline at end of file +MEDIPOST_RECIPIENT=your-medipost-recipient + +EMAIL_SENDER= +EMAIL_USER= # refer to your email provider's documentation +EMAIL_PASSWORD= # refer to your email provider's documentation +EMAIL_HOST= # refer to your email provider's documentation +EMAIL_PORT= # or 465 for SSL +EMAIL_TLS= # or false for SSL (see provider documentation) \ No newline at end of file diff --git a/app/(marketing)/page.tsx b/app/(marketing)/page.tsx index d1c8b2d..09dd6bc 100644 --- a/app/(marketing)/page.tsx +++ b/app/(marketing)/page.tsx @@ -1,6 +1,6 @@ import Link from 'next/link'; -import { MedReportTitle } from '@/components/med-report-title'; +import { MedReportLogo } from '@/components/med-report-title'; import { ArrowRightIcon } from 'lucide-react'; import { CtaButton, Hero } from '@kit/ui/marketing'; @@ -13,7 +13,7 @@ function Home() {
} + title={} subtitle={ diff --git a/app/(public)/register-company/page.tsx b/app/(public)/register-company/page.tsx index 905e0e6..c4a75df 100644 --- a/app/(public)/register-company/page.tsx +++ b/app/(public)/register-company/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { MedReportTitle } from "@/components/med-report-title"; +import { MedReportLogo } from "@/components/med-report-title"; import React from "react"; import { yupResolver } from "@hookform/resolvers/yup"; import { useForm } from "react-hook-form"; @@ -45,7 +45,7 @@ export default function RegisterCompany() { return (
- +

Ettevõtte andmed

Pakkumise saamiseks palun sisesta ettevõtte andmed millega MedReport diff --git a/app/(public)/register-company/success/page.tsx b/app/(public)/register-company/success/page.tsx index 9682cff..3ed223d 100644 --- a/app/(public)/register-company/success/page.tsx +++ b/app/(public)/register-company/success/page.tsx @@ -1,11 +1,12 @@ -import { MedReportTitle } from "@/components/med-report-title"; +import { MedReportLogo } from "@/components/med-report-title"; +import { Button } from "@kit/ui/button"; import Image from "next/image"; import Link from "next/link"; export default function CompanyRegistrationSuccess() { return (

- +
- - - ); + return ; } export function AppLogo({ diff --git a/components/med-report-title.tsx b/components/med-report-title.tsx index e8398cb..bf809f8 100644 --- a/components/med-report-title.tsx +++ b/components/med-report-title.tsx @@ -1,7 +1,8 @@ +import { cn } from "@/lib/utils"; import { MedReportSmallLogo } from "@/public/assets/med-report-small-logo"; -export const MedReportTitle = () => ( -
+export const MedReportLogo = ({ className }: { className?: string }) => ( +
MedReport diff --git a/lib/dev-mock-modules.ts b/lib/dev-mock-modules.ts index b433cce..5861368 100644 --- a/lib/dev-mock-modules.ts +++ b/lib/dev-mock-modules.ts @@ -32,4 +32,4 @@ export const setUser = noop('Sentry.setUser'); export const loadStripe = noop('Stripe.loadStripe'); // Nodemailer -export const createTransport = noop('Nodemailer.createTransport'); +// export const createTransport = noop('Nodemailer.createTransport'); diff --git a/next.config.mjs b/next.config.mjs index 0ffa657..73c7188 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -129,7 +129,7 @@ function getModulesAliases() { const excludeSentry = monitoringProvider !== 'sentry'; const excludeBaselime = monitoringProvider !== 'baselime'; const excludeStripe = billingProvider !== 'stripe'; - const excludeNodemailer = mailerProvider !== 'nodemailer'; + // const excludeNodemailer = mailerProvider !== 'nodemailer'; const excludeTurnstile = !captchaProvider; /** @type {Record} */ @@ -151,9 +151,9 @@ function getModulesAliases() { aliases['@stripe/stripe-js'] = noopPath; } - if (excludeNodemailer) { - aliases['nodemailer'] = noopPath; - } + // if (excludeNodemailer) { + // aliases['nodemailer'] = noopPath; + // } if (excludeTurnstile) { aliases['@marsidev/react-turnstile'] = noopPath; diff --git a/package.json b/package.json index e79bb89..be13199 100644 --- a/package.json +++ b/package.json @@ -93,6 +93,7 @@ "@types/react-dom": "19.1.5", "babel-plugin-react-compiler": "19.1.0-rc.2", "cssnano": "^7.0.7", + "dotenv": "^16.5.0", "pino-pretty": "^13.0.0", "prettier": "^3.5.3", "react-hook-form": "^7.57.0", @@ -100,8 +101,7 @@ "tailwindcss": "4.1.7", "tailwindcss-animate": "^1.0.7", "typescript": "^5.8.3", - "yup": "^1.6.1", - "dotenv": "^16.5.0" + "yup": "^1.6.1" }, "prettier": "@kit/prettier-config", "browserslist": [ diff --git a/packages/features/accounts/src/components/account-selector.tsx b/packages/features/accounts/src/components/account-selector.tsx index acf096d..909a929 100644 --- a/packages/features/accounts/src/components/account-selector.tsx +++ b/packages/features/accounts/src/components/account-selector.tsx @@ -24,6 +24,7 @@ import { cn } from '@kit/ui/utils'; import { CreateTeamAccountDialog } from '../../../team-accounts/src/components/create-team-account-dialog'; import { usePersonalAccountData } from '../hooks/use-personal-account-data'; +import { useUserWorkspace } from '../hooks/use-user-workspace'; interface AccountSelectorProps { accounts: Array<{ @@ -63,6 +64,7 @@ export function AccountSelector({ const [isCreatingAccount, setIsCreatingAccount] = useState(false); const { t } = useTranslation('teams'); const personalData = usePersonalAccountData(userId); + const { user } = useUserWorkspace(); const value = useMemo(() => { return selectedAccount ?? PERSONAL_ACCOUNT_SLUG; @@ -89,6 +91,16 @@ export function AccountSelector({ ); + const isSuperAdmin = useMemo(() => { + const factors = user?.factors ?? []; + const hasAdminRole = user?.app_metadata.role === 'super-admin'; + const hasTotpFactor = factors.some( + (factor) => factor.factor_type === 'totp' && factor.status === 'verified', + ); + + return hasAdminRole && hasTotpFactor; + }, [user]); + return ( <> @@ -172,7 +184,6 @@ export function AccountSelector({ > - - +
-
- Team Members + Company Employees
diff --git a/packages/features/admin/src/components/admin-accounts-table.tsx b/packages/features/admin/src/components/admin-accounts-table.tsx index abaee2d..06a14c7 100644 --- a/packages/features/admin/src/components/admin-accounts-table.tsx +++ b/packages/features/admin/src/components/admin-accounts-table.tsx @@ -132,7 +132,7 @@ function AccountsTableFilters(props: { Account Type All accounts - Team + Company Personal @@ -183,7 +183,7 @@ function getColumns(): ColumnDef[] { id: 'type', header: 'Type', cell: ({ row }) => { - return row.original.is_personal_account ? 'Personal' : 'Team'; + return row.original.is_personal_account ? 'Personal' : 'Company'; }, }, { @@ -248,7 +248,7 @@ function getColumns(): ColumnDef[] { e.preventDefault()}> - Delete Team Account + Delete Company Account diff --git a/packages/features/admin/src/components/admin-dashboard.tsx b/packages/features/admin/src/components/admin-dashboard.tsx index 997d5a5..0492441 100644 --- a/packages/features/admin/src/components/admin-dashboard.tsx +++ b/packages/features/admin/src/components/admin-dashboard.tsx @@ -36,10 +36,10 @@ export async function AdminDashboard() { - Team Accounts + Company Accounts - The number of team accounts that have been created. + The number of company accounts that have been created. @@ -49,43 +49,6 @@ export async function AdminDashboard() {
- - - - Paying Customers - - The number of paying customers with active subscriptions. - - - - -
-
{data.subscriptions}
-
-
-
- - - - Trials - - - The number of trial subscriptions currently active. - - - - -
-
{data.trials}
-
-
-
- -
-

- The above data is estimated and may not be 100% accurate. -

-
); } diff --git a/packages/features/admin/src/components/admin-members-table.tsx b/packages/features/admin/src/components/admin-members-table.tsx index d00e51c..8d256be 100644 --- a/packages/features/admin/src/components/admin-members-table.tsx +++ b/packages/features/admin/src/components/admin-members-table.tsx @@ -52,7 +52,7 @@ function getColumns(): ColumnDef[] { { header: 'Role', cell: ({ row }) => { - return row.original.role; + return row.original.role === 'owner' ? 'HR' : 'Employee'; }, }, { diff --git a/public/locales/en/auth.json b/public/locales/en/auth.json index 3bb81d4..7db0925 100644 --- a/public/locales/en/auth.json +++ b/public/locales/en/auth.json @@ -63,8 +63,8 @@ "sendingEmailCode": "Sending code...", "resetPasswordError": "Sorry, we could not reset your password. Please try again.", "emailPlaceholder": "your@email.com", - "inviteAlertHeading": "You have been invited to join a team", - "inviteAlertBody": "Please sign in or sign up to accept the invite and join the team.", + "inviteAlertHeading": "You have been invited to join a company", + "inviteAlertBody": "Please sign in or sign up to accept the invite and join the company.", "acceptTermsAndConditions": "I accept the and ", "termsOfService": "Terms of Service", "privacyPolicy": "Privacy Policy", diff --git a/public/locales/en/billing.json b/public/locales/en/billing.json index 9efef35..84c849e 100644 --- a/public/locales/en/billing.json +++ b/public/locales/en/billing.json @@ -18,8 +18,8 @@ "checkoutSuccessBackButton": "Proceed to App", "cannotManageBillingAlertTitle": "You cannot manage billing", "cannotManageBillingAlertDescription": "You do not have permissions to manage billing. Please contact your account owner.", - "manageTeamPlan": "Manage your Team Plan", - "manageTeamPlanDescription": "Choose a plan that fits your team's needs. You can upgrade or downgrade your plan at any time.", + "manageTeamPlan": "Manage your Company Plan", + "manageTeamPlanDescription": "Choose a plan that fits your company's needs. You can upgrade or downgrade your plan at any time.", "basePlan": "Base Plan", "billingInterval": { "label": "Choose your billing interval", @@ -34,9 +34,9 @@ "redirectingToPayment": "Redirecting to checkout. Please wait...", "proceedToPayment": "Proceed to Payment", "startTrial": "Start Trial", - "perTeamMember": "Per team member", + "perTeamMember": "Per company employee", "perUnit": "Per {{unit}} usage", - "teamMembers": "Team Members", + "teamMembers": "Company Employees", "includedUpTo": "Up to {{upTo}} {{unit}} included in the plan", "fromPreviousTierUpTo": "for each {{unit}} for the next {{ upTo }} {{ unit }}", "andAbove": "above {{ previousTier }} {{ unit }}", diff --git a/public/locales/en/common.json b/public/locales/en/common.json index c194ce3..8aade69 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -1,8 +1,8 @@ { "homeTabLabel": "Home", "homeTabDescription": "Welcome to your home page", - "accountMembers": "Team Members", - "membersTabDescription": "Here you can manage the members of your team.", + "accountMembers": "Company Employees", + "membersTabDescription": "Here you can manage the employees of your company.", "billingTabLabel": "Billing", "billingTabDescription": "Manage your billing and subscription", "dashboardTabLabel": "Dashboard", @@ -58,7 +58,7 @@ "routes": { "home": "Home", "account": "Account", - "members": "Members", + "members": "Employees", "billing": "Billing", "dashboard": "Dashboard", "settings": "Settings", @@ -70,7 +70,7 @@ "label": "Owner" }, "member": { - "label": "Member" + "label": "Employee" } }, "otp": { diff --git a/public/locales/en/teams.json b/public/locales/en/teams.json index 2a0b614..d09d78d 100644 --- a/public/locales/en/teams.json +++ b/public/locales/en/teams.json @@ -4,26 +4,26 @@ }, "settings": { "pageTitle": "Settings", - "pageDescription": "Manage your Team details", - "teamLogo": "Team Logo", - "teamLogoDescription": "Update your team's logo to make it easier to identify", - "teamName": "Team Name", - "teamNameDescription": "Update your team's name", + "pageDescription": "Manage your Company details", + "teamLogo": "Company Logo", + "teamLogoDescription": "Update your company's logo to make it easier to identify", + "teamName": "Company Name", + "teamNameDescription": "Update your company's name", "dangerZone": "Danger Zone", "dangerZoneDescription": "This section contains actions that are irreversible" }, "members": { - "pageTitle": "Members" + "pageTitle": "Employees" }, "billing": { "pageTitle": "Billing" }, - "yourTeams": "Your Teams ({{teamsCount}})", - "createTeam": "Create a Team", - "creatingTeam": "Creating Team...", + "yourTeams": "Your Companies ({{teamsCount}})", + "createTeam": "Create a Company", + "creatingTeam": "Creating Company...", "personalAccount": "Personal Account", "searchAccount": "Search Account...", - "membersTabLabel": "Members", + "membersTabLabel": "Employees", "memberName": "Name", "youLabel": "You", "emailLabel": "Email", @@ -31,108 +31,108 @@ "primaryOwnerLabel": "Primary Owner", "joinedAtLabel": "Joined at", "invitedAtLabel": "Invited at", - "inviteMembersPageSubheading": "Invite members to your Team", - "createTeamModalHeading": "Create Team", - "createTeamModalDescription": "Create a new Team to manage your projects and members.", - "teamNameLabel": "Team Name", - "teamNameDescription": "Your team name should be unique and descriptive", - "createTeamSubmitLabel": "Create Team", - "createTeamSuccess": "Team created successfully", - "createTeamError": "Team not created. Please try again.", - "createTeamLoading": "Creating team...", + "inviteMembersPageSubheading": "Invite employees to your Company", + "createTeamModalHeading": "Create Company", + "createTeamModalDescription": "Create a new Company to manage your projects and employees.", + "teamNameLabel": "Company Name", + "teamNameDescription": "Your company name should be unique and descriptive", + "createTeamSubmitLabel": "Create Company", + "createTeamSuccess": "Company created successfully", + "createTeamError": "Company not created. Please try again.", + "createTeamLoading": "Creating company...", "settingsPageLabel": "General", - "createTeamDropdownLabel": "New team", + "createTeamDropdownLabel": "New company", "changeRole": "Change Role", "removeMember": "Remove from Account", - "inviteMembersSuccess": "Members invited successfully!", + "inviteMembersSuccess": "Employees invited successfully!", "inviteMembersError": "Sorry, we encountered an error! Please try again", - "inviteMembersLoading": "Inviting members...", + "inviteMembersLoading": "Inviting employees...", "removeInviteButtonLabel": "Remove invite", "addAnotherMemberButtonLabel": "Add another one", "inviteMembersButtonLabel": "Send Invites", "removeMemberModalHeading": "You are removing this user", - "removeMemberModalDescription": "Remove this member from the team. They will no longer have access to the team.", - "removeMemberSuccessMessage": "Member removed successfully", + "removeMemberModalDescription": "Remove this employee from the company. They will no longer have access to the company.", + "removeMemberSuccessMessage": "Employee removed successfully", "removeMemberErrorMessage": "Sorry, we encountered an error. Please try again", - "removeMemberErrorHeading": "Sorry, we couldn't remove the selected member.", - "removeMemberLoadingMessage": "Removing member...", - "removeMemberSubmitLabel": "Remove User from Team", + "removeMemberErrorHeading": "Sorry, we couldn't remove the selected employee.", + "removeMemberLoadingMessage": "Removing employee...", + "removeMemberSubmitLabel": "Remove User from Company", "chooseDifferentRoleError": "Role is the same as the current one", "updateRole": "Update Role", "updateRoleLoadingMessage": "Updating role...", "updateRoleSuccessMessage": "Role updated successfully", "updatingRoleErrorMessage": "Sorry, we encountered an error. Please try again.", - "updateMemberRoleModalHeading": "Update Member's Role", + "updateMemberRoleModalHeading": "Update Employee's Role", "updateMemberRoleModalDescription": "Change the role of the selected member. The role determines the permissions of the member.", "roleMustBeDifferent": "Role must be different from the current one", "memberRoleInputLabel": "Member role", "updateRoleDescription": "Pick a role for this member.", "updateRoleSubmitLabel": "Update Role", "transferOwnership": "Transfer Ownership", - "transferOwnershipDescription": "Transfer ownership of the team to another member.", + "transferOwnershipDescription": "Transfer ownership of the company account to another employee.", "transferOwnershipInputLabel": "Please type TRANSFER to confirm the transfer of ownership.", - "transferOwnershipInputDescription": "By transferring ownership, you will no longer be the primary owner of the team.", + "transferOwnershipInputDescription": "By transferring ownership, you will no longer be the primary owner of the company account.", "deleteInvitation": "Delete Invitation", - "deleteInvitationDialogDescription": "You are about to delete the invitation. The user will no longer be able to join the team.", + "deleteInvitationDialogDescription": "You are about to delete the invitation. The user will no longer be able to join the company account.", "deleteInviteSuccessMessage": "Invite deleted successfully", "deleteInviteErrorMessage": "Invite not deleted. Please try again.", "deleteInviteLoadingMessage": "Deleting invite. Please wait...", "confirmDeletingMemberInvite": "You are deleting the invite to {{ email }}", - "transferOwnershipDisclaimer": "You are transferring ownership of the selected team to {{ member }}.", + "transferOwnershipDisclaimer": "You are transferring ownership of the selected company account to {{ member }}.", "transferringOwnership": "Transferring ownership...", "transferOwnershipSuccess": "Ownership successfully transferred", "transferOwnershipError": "Sorry, we could not transfer ownership to the selected member. Please try again.", "deleteInviteSubmitLabel": "Delete Invite", "youBadgeLabel": "You", - "updateTeamLoadingMessage": "Updating Team...", - "updateTeamSuccessMessage": "Team successfully updated", - "updateTeamErrorMessage": "Could not update Team. Please try again.", + "updateTeamLoadingMessage": "Updating Company...", + "updateTeamSuccessMessage": "Company successfully updated", + "updateTeamErrorMessage": "Could not update Company. Please try again.", "updateLogoErrorMessage": "Could not update Logo. Please try again.", - "teamNameInputLabel": "Team Name", - "teamLogoInputHeading": "Upload your team's Logo", - "teamLogoInputSubheading": "Please choose a photo to upload as your team logo.", - "updateTeamSubmitLabel": "Update Team", - "inviteMembersHeading": "Invite Members to your Team", - "inviteMembersDescription": "Invite members to your team by entering their email and role.", - "emailPlaceholder": "member@email.com", - "membersPageHeading": "Members", - "inviteMembersButton": "Invite Members", - "invitingMembers": "Inviting members...", - "inviteMembersSuccessMessage": "Members invited successfully", - "inviteMembersErrorMessage": "Sorry, members could not be invited. Please try again.", + "teamNameInputLabel": "Company Name", + "teamLogoInputHeading": "Upload your company's Logo", + "teamLogoInputSubheading": "Please choose a photo to upload as your company logo.", + "updateTeamSubmitLabel": "Update Company", + "inviteMembersHeading": "Invite Employees to your Company", + "inviteMembersDescription": "Invite employees to your company by entering their email and role.", + "emailPlaceholder": "employee@email.com", + "membersPageHeading": "Employees", + "inviteMembersButton": "Invite Employees", + "invitingMembers": "Inviting employees...", + "inviteMembersSuccessMessage": "Employees invited successfully", + "inviteMembersErrorMessage": "Sorry, employees could not be invited. Please try again.", "pendingInvitesHeading": "Pending Invites", - "pendingInvitesDescription": " Here you can manage the pending invitations to your team.", + "pendingInvitesDescription": " Here you can manage the pending invitations to your company.", "noPendingInvites": "No pending invites found", - "loadingMembers": "Loading members...", - "loadMembersError": "Sorry, we couldn't fetch your team's members.", - "loadInvitedMembersError": "Sorry, we couldn't fetch your team's invited members.", - "loadingInvitedMembers": "Loading invited members...", + "loadingMembers": "Loading employees...", + "loadMembersError": "Sorry, we couldn't fetch your company's employees.", + "loadInvitedMembersError": "Sorry, we couldn't fetch your company's invited employees.", + "loadingInvitedMembers": "Loading invited employees...", "invitedBadge": "Invited", "duplicateInviteEmailError": "You have already entered this email address", "invitingOwnAccountError": "Hey, that's your email!", "dangerZone": "Danger Zone", - "dangerZoneSubheading": "Delete or leave your team", - "deleteTeam": "Delete Team", - "deleteTeamDescription": "This action cannot be undone. All data associated with this team will be deleted.", - "deletingTeam": "Deleting team", - "deleteTeamModalHeading": "Deleting Team", - "deletingTeamDescription": "You are about to delete the team {{ teamName }}. This action cannot be undone.", - "deleteTeamInputField": "Type the name of the team to confirm", - "leaveTeam": "Leave Team", - "leavingTeamModalHeading": "Leaving Team", - "leavingTeamModalDescription": "You are about to leave this team. You will no longer have access to it.", - "leaveTeamDescription": "Click the button below to leave the team. Remember, you will no longer have access to it and will need to be re-invited to join.", - "deleteTeamDisclaimer": "You are deleting the team {{ teamName }}. This action cannot be undone.", - "leaveTeamDisclaimer": "You are leaving the team {{ teamName }}. You will no longer have access to it.", - "deleteTeamErrorHeading": "Sorry, we couldn't delete your team.", - "leaveTeamErrorHeading": "Sorry, we couldn't leave your team.", - "searchMembersPlaceholder": "Search members", - "createTeamErrorHeading": "Sorry, we couldn't create your team.", - "createTeamErrorMessage": "We encountered an error creating your team. Please try again.", - "transferTeamErrorHeading": "Sorry, we couldn't transfer ownership of your team.", - "transferTeamErrorMessage": "We encountered an error transferring ownership of your team. Please try again.", - "updateRoleErrorHeading": "Sorry, we couldn't update the role of the selected member.", - "updateRoleErrorMessage": "We encountered an error updating the role of the selected member. Please try again.", + "dangerZoneSubheading": "Delete or leave your company", + "deleteTeam": "Delete Company", + "deleteTeamDescription": "This action cannot be undone. All data associated with this company will be deleted.", + "deletingTeam": "Deleting company", + "deleteTeamModalHeading": "Deleting Company", + "deletingTeamDescription": "You are about to delete the company {{ teamName }}. This action cannot be undone.", + "deleteTeamInputField": "Type the name of the company to confirm", + "leaveTeam": "Leave Company", + "leavingTeamModalHeading": "Leaving Company", + "leavingTeamModalDescription": "You are about to leave this company. You will no longer have access to it.", + "leaveTeamDescription": "Click the button below to leave the company. Remember, you will no longer have access to it and will need to be re-invited to join.", + "deleteTeamDisclaimer": "You are deleting the company {{ teamName }}. This action cannot be undone.", + "leaveTeamDisclaimer": "You are leaving the company {{ teamName }}. You will no longer have access to it.", + "deleteTeamErrorHeading": "Sorry, we couldn't delete your company.", + "leaveTeamErrorHeading": "Sorry, we couldn't leave your company.", + "searchMembersPlaceholder": "Search employees", + "createTeamErrorHeading": "Sorry, we couldn't create your company.", + "createTeamErrorMessage": "We encountered an error creating your company. Please try again.", + "transferTeamErrorHeading": "Sorry, we couldn't transfer ownership of your company account.", + "transferTeamErrorMessage": "We encountered an error transferring ownership of your company account. Please try again.", + "updateRoleErrorHeading": "Sorry, we couldn't update the role of the selected employee.", + "updateRoleErrorMessage": "We encountered an error updating the role of the selected employee. Please try again.", "searchInvitations": "Search Invitations", "updateInvitation": "Update Invitation", "removeInvitation": "Remove Invitation", @@ -144,20 +144,20 @@ "active": "Active", "inviteStatus": "Status", "inviteNotFoundOrExpired": "Invite not found or expired", - "inviteNotFoundOrExpiredDescription": "The invite you are looking for is either expired or does not exist. Please contact the team owner to renew the invite.", + "inviteNotFoundOrExpiredDescription": "The invite you are looking for is either expired or does not exist. Please contact the company HR to renew the invite.", "backToHome": "Back to Home", - "renewInvitationDialogDescription": "You are about to renew the invitation to {{ email }}. The user will be able to join the team.", + "renewInvitationDialogDescription": "You are about to renew the invitation to {{ email }}. The user will be able to join the company.", "renewInvitationErrorTitle": "Sorry, we couldn't renew the invitation.", "renewInvitationErrorDescription": "We encountered an error renewing the invitation. Please try again.", "signInWithDifferentAccount": "Sign in with a different account", "signInWithDifferentAccountDescription": "If you wish to accept the invitation with a different account, please sign out and back in with the account you wish to use.", "acceptInvitationHeading": "Accept Invitation to join {{accountName}}", - "acceptInvitationDescription": "You have been invited to join the team {{accountName}}. If you wish to accept the invitation, please click the button below.", + "acceptInvitationDescription": "You have been invited to join the company {{accountName}}. If you wish to accept the invitation, please click the button below.", "continueAs": "Continue as {{email}}", - "joinTeamAccount": "Join Team", - "joiningTeam": "Joining team...", - "leaveTeamInputLabel": "Please type LEAVE to confirm leaving the team.", - "leaveTeamInputDescription": "By leaving the team, you will no longer have access to it.", + "joinTeamAccount": "Join Company", + "joiningTeam": "Joining company...", + "leaveTeamInputLabel": "Please type LEAVE to confirm leaving the company.", + "leaveTeamInputDescription": "By leaving the company, you will no longer have access to it.", "reservedNameError": "This name is reserved. Please choose a different one.", "specialCharactersError": "This name cannot contain special characters. Please choose a different one." } diff --git a/public/locales/et/account.json b/public/locales/et/account.json index 3526791..28ee8d9 100644 --- a/public/locales/et/account.json +++ b/public/locales/et/account.json @@ -113,5 +113,5 @@ "createTeam": "Create a team to get started.", "createTeamButtonLabel": "Create a Team", "createCompanyAccount": "Create Company Account", - "requestCompanyAccount": "Küsi pakkumist" + "requestCompanyAccount": "Request Company Account" } diff --git a/public/locales/et/auth.json b/public/locales/et/auth.json index 3bb81d4..7db0925 100644 --- a/public/locales/et/auth.json +++ b/public/locales/et/auth.json @@ -63,8 +63,8 @@ "sendingEmailCode": "Sending code...", "resetPasswordError": "Sorry, we could not reset your password. Please try again.", "emailPlaceholder": "your@email.com", - "inviteAlertHeading": "You have been invited to join a team", - "inviteAlertBody": "Please sign in or sign up to accept the invite and join the team.", + "inviteAlertHeading": "You have been invited to join a company", + "inviteAlertBody": "Please sign in or sign up to accept the invite and join the company.", "acceptTermsAndConditions": "I accept the and ", "termsOfService": "Terms of Service", "privacyPolicy": "Privacy Policy", diff --git a/public/locales/et/billing.json b/public/locales/et/billing.json index 9efef35..84c849e 100644 --- a/public/locales/et/billing.json +++ b/public/locales/et/billing.json @@ -18,8 +18,8 @@ "checkoutSuccessBackButton": "Proceed to App", "cannotManageBillingAlertTitle": "You cannot manage billing", "cannotManageBillingAlertDescription": "You do not have permissions to manage billing. Please contact your account owner.", - "manageTeamPlan": "Manage your Team Plan", - "manageTeamPlanDescription": "Choose a plan that fits your team's needs. You can upgrade or downgrade your plan at any time.", + "manageTeamPlan": "Manage your Company Plan", + "manageTeamPlanDescription": "Choose a plan that fits your company's needs. You can upgrade or downgrade your plan at any time.", "basePlan": "Base Plan", "billingInterval": { "label": "Choose your billing interval", @@ -34,9 +34,9 @@ "redirectingToPayment": "Redirecting to checkout. Please wait...", "proceedToPayment": "Proceed to Payment", "startTrial": "Start Trial", - "perTeamMember": "Per team member", + "perTeamMember": "Per company employee", "perUnit": "Per {{unit}} usage", - "teamMembers": "Team Members", + "teamMembers": "Company Employees", "includedUpTo": "Up to {{upTo}} {{unit}} included in the plan", "fromPreviousTierUpTo": "for each {{unit}} for the next {{ upTo }} {{ unit }}", "andAbove": "above {{ previousTier }} {{ unit }}", diff --git a/public/locales/et/common.json b/public/locales/et/common.json index c194ce3..8aade69 100644 --- a/public/locales/et/common.json +++ b/public/locales/et/common.json @@ -1,8 +1,8 @@ { "homeTabLabel": "Home", "homeTabDescription": "Welcome to your home page", - "accountMembers": "Team Members", - "membersTabDescription": "Here you can manage the members of your team.", + "accountMembers": "Company Employees", + "membersTabDescription": "Here you can manage the employees of your company.", "billingTabLabel": "Billing", "billingTabDescription": "Manage your billing and subscription", "dashboardTabLabel": "Dashboard", @@ -58,7 +58,7 @@ "routes": { "home": "Home", "account": "Account", - "members": "Members", + "members": "Employees", "billing": "Billing", "dashboard": "Dashboard", "settings": "Settings", @@ -70,7 +70,7 @@ "label": "Owner" }, "member": { - "label": "Member" + "label": "Employee" } }, "otp": { diff --git a/public/locales/et/marketing.json b/public/locales/et/marketing.json index 96420bd..3deb11a 100644 --- a/public/locales/et/marketing.json +++ b/public/locales/et/marketing.json @@ -36,5 +36,5 @@ "contactErrorDescription": "An error occurred while sending your message. Please try again later", "footerDescription": "Here you can add a description about your company or product", "copyright": "© Copyright {{year}} {{product}}. All Rights Reserved.", - "heroSubtitle": "Lihtne, mugav ja kiire ülevaade Sinu tervise seisundist" + "heroSubtitle": "Lihtne, mugav ja kiire ülevaade oma tervisest" } diff --git a/public/locales/et/teams.json b/public/locales/et/teams.json index 2a0b614..d09d78d 100644 --- a/public/locales/et/teams.json +++ b/public/locales/et/teams.json @@ -4,26 +4,26 @@ }, "settings": { "pageTitle": "Settings", - "pageDescription": "Manage your Team details", - "teamLogo": "Team Logo", - "teamLogoDescription": "Update your team's logo to make it easier to identify", - "teamName": "Team Name", - "teamNameDescription": "Update your team's name", + "pageDescription": "Manage your Company details", + "teamLogo": "Company Logo", + "teamLogoDescription": "Update your company's logo to make it easier to identify", + "teamName": "Company Name", + "teamNameDescription": "Update your company's name", "dangerZone": "Danger Zone", "dangerZoneDescription": "This section contains actions that are irreversible" }, "members": { - "pageTitle": "Members" + "pageTitle": "Employees" }, "billing": { "pageTitle": "Billing" }, - "yourTeams": "Your Teams ({{teamsCount}})", - "createTeam": "Create a Team", - "creatingTeam": "Creating Team...", + "yourTeams": "Your Companies ({{teamsCount}})", + "createTeam": "Create a Company", + "creatingTeam": "Creating Company...", "personalAccount": "Personal Account", "searchAccount": "Search Account...", - "membersTabLabel": "Members", + "membersTabLabel": "Employees", "memberName": "Name", "youLabel": "You", "emailLabel": "Email", @@ -31,108 +31,108 @@ "primaryOwnerLabel": "Primary Owner", "joinedAtLabel": "Joined at", "invitedAtLabel": "Invited at", - "inviteMembersPageSubheading": "Invite members to your Team", - "createTeamModalHeading": "Create Team", - "createTeamModalDescription": "Create a new Team to manage your projects and members.", - "teamNameLabel": "Team Name", - "teamNameDescription": "Your team name should be unique and descriptive", - "createTeamSubmitLabel": "Create Team", - "createTeamSuccess": "Team created successfully", - "createTeamError": "Team not created. Please try again.", - "createTeamLoading": "Creating team...", + "inviteMembersPageSubheading": "Invite employees to your Company", + "createTeamModalHeading": "Create Company", + "createTeamModalDescription": "Create a new Company to manage your projects and employees.", + "teamNameLabel": "Company Name", + "teamNameDescription": "Your company name should be unique and descriptive", + "createTeamSubmitLabel": "Create Company", + "createTeamSuccess": "Company created successfully", + "createTeamError": "Company not created. Please try again.", + "createTeamLoading": "Creating company...", "settingsPageLabel": "General", - "createTeamDropdownLabel": "New team", + "createTeamDropdownLabel": "New company", "changeRole": "Change Role", "removeMember": "Remove from Account", - "inviteMembersSuccess": "Members invited successfully!", + "inviteMembersSuccess": "Employees invited successfully!", "inviteMembersError": "Sorry, we encountered an error! Please try again", - "inviteMembersLoading": "Inviting members...", + "inviteMembersLoading": "Inviting employees...", "removeInviteButtonLabel": "Remove invite", "addAnotherMemberButtonLabel": "Add another one", "inviteMembersButtonLabel": "Send Invites", "removeMemberModalHeading": "You are removing this user", - "removeMemberModalDescription": "Remove this member from the team. They will no longer have access to the team.", - "removeMemberSuccessMessage": "Member removed successfully", + "removeMemberModalDescription": "Remove this employee from the company. They will no longer have access to the company.", + "removeMemberSuccessMessage": "Employee removed successfully", "removeMemberErrorMessage": "Sorry, we encountered an error. Please try again", - "removeMemberErrorHeading": "Sorry, we couldn't remove the selected member.", - "removeMemberLoadingMessage": "Removing member...", - "removeMemberSubmitLabel": "Remove User from Team", + "removeMemberErrorHeading": "Sorry, we couldn't remove the selected employee.", + "removeMemberLoadingMessage": "Removing employee...", + "removeMemberSubmitLabel": "Remove User from Company", "chooseDifferentRoleError": "Role is the same as the current one", "updateRole": "Update Role", "updateRoleLoadingMessage": "Updating role...", "updateRoleSuccessMessage": "Role updated successfully", "updatingRoleErrorMessage": "Sorry, we encountered an error. Please try again.", - "updateMemberRoleModalHeading": "Update Member's Role", + "updateMemberRoleModalHeading": "Update Employee's Role", "updateMemberRoleModalDescription": "Change the role of the selected member. The role determines the permissions of the member.", "roleMustBeDifferent": "Role must be different from the current one", "memberRoleInputLabel": "Member role", "updateRoleDescription": "Pick a role for this member.", "updateRoleSubmitLabel": "Update Role", "transferOwnership": "Transfer Ownership", - "transferOwnershipDescription": "Transfer ownership of the team to another member.", + "transferOwnershipDescription": "Transfer ownership of the company account to another employee.", "transferOwnershipInputLabel": "Please type TRANSFER to confirm the transfer of ownership.", - "transferOwnershipInputDescription": "By transferring ownership, you will no longer be the primary owner of the team.", + "transferOwnershipInputDescription": "By transferring ownership, you will no longer be the primary owner of the company account.", "deleteInvitation": "Delete Invitation", - "deleteInvitationDialogDescription": "You are about to delete the invitation. The user will no longer be able to join the team.", + "deleteInvitationDialogDescription": "You are about to delete the invitation. The user will no longer be able to join the company account.", "deleteInviteSuccessMessage": "Invite deleted successfully", "deleteInviteErrorMessage": "Invite not deleted. Please try again.", "deleteInviteLoadingMessage": "Deleting invite. Please wait...", "confirmDeletingMemberInvite": "You are deleting the invite to {{ email }}", - "transferOwnershipDisclaimer": "You are transferring ownership of the selected team to {{ member }}.", + "transferOwnershipDisclaimer": "You are transferring ownership of the selected company account to {{ member }}.", "transferringOwnership": "Transferring ownership...", "transferOwnershipSuccess": "Ownership successfully transferred", "transferOwnershipError": "Sorry, we could not transfer ownership to the selected member. Please try again.", "deleteInviteSubmitLabel": "Delete Invite", "youBadgeLabel": "You", - "updateTeamLoadingMessage": "Updating Team...", - "updateTeamSuccessMessage": "Team successfully updated", - "updateTeamErrorMessage": "Could not update Team. Please try again.", + "updateTeamLoadingMessage": "Updating Company...", + "updateTeamSuccessMessage": "Company successfully updated", + "updateTeamErrorMessage": "Could not update Company. Please try again.", "updateLogoErrorMessage": "Could not update Logo. Please try again.", - "teamNameInputLabel": "Team Name", - "teamLogoInputHeading": "Upload your team's Logo", - "teamLogoInputSubheading": "Please choose a photo to upload as your team logo.", - "updateTeamSubmitLabel": "Update Team", - "inviteMembersHeading": "Invite Members to your Team", - "inviteMembersDescription": "Invite members to your team by entering their email and role.", - "emailPlaceholder": "member@email.com", - "membersPageHeading": "Members", - "inviteMembersButton": "Invite Members", - "invitingMembers": "Inviting members...", - "inviteMembersSuccessMessage": "Members invited successfully", - "inviteMembersErrorMessage": "Sorry, members could not be invited. Please try again.", + "teamNameInputLabel": "Company Name", + "teamLogoInputHeading": "Upload your company's Logo", + "teamLogoInputSubheading": "Please choose a photo to upload as your company logo.", + "updateTeamSubmitLabel": "Update Company", + "inviteMembersHeading": "Invite Employees to your Company", + "inviteMembersDescription": "Invite employees to your company by entering their email and role.", + "emailPlaceholder": "employee@email.com", + "membersPageHeading": "Employees", + "inviteMembersButton": "Invite Employees", + "invitingMembers": "Inviting employees...", + "inviteMembersSuccessMessage": "Employees invited successfully", + "inviteMembersErrorMessage": "Sorry, employees could not be invited. Please try again.", "pendingInvitesHeading": "Pending Invites", - "pendingInvitesDescription": " Here you can manage the pending invitations to your team.", + "pendingInvitesDescription": " Here you can manage the pending invitations to your company.", "noPendingInvites": "No pending invites found", - "loadingMembers": "Loading members...", - "loadMembersError": "Sorry, we couldn't fetch your team's members.", - "loadInvitedMembersError": "Sorry, we couldn't fetch your team's invited members.", - "loadingInvitedMembers": "Loading invited members...", + "loadingMembers": "Loading employees...", + "loadMembersError": "Sorry, we couldn't fetch your company's employees.", + "loadInvitedMembersError": "Sorry, we couldn't fetch your company's invited employees.", + "loadingInvitedMembers": "Loading invited employees...", "invitedBadge": "Invited", "duplicateInviteEmailError": "You have already entered this email address", "invitingOwnAccountError": "Hey, that's your email!", "dangerZone": "Danger Zone", - "dangerZoneSubheading": "Delete or leave your team", - "deleteTeam": "Delete Team", - "deleteTeamDescription": "This action cannot be undone. All data associated with this team will be deleted.", - "deletingTeam": "Deleting team", - "deleteTeamModalHeading": "Deleting Team", - "deletingTeamDescription": "You are about to delete the team {{ teamName }}. This action cannot be undone.", - "deleteTeamInputField": "Type the name of the team to confirm", - "leaveTeam": "Leave Team", - "leavingTeamModalHeading": "Leaving Team", - "leavingTeamModalDescription": "You are about to leave this team. You will no longer have access to it.", - "leaveTeamDescription": "Click the button below to leave the team. Remember, you will no longer have access to it and will need to be re-invited to join.", - "deleteTeamDisclaimer": "You are deleting the team {{ teamName }}. This action cannot be undone.", - "leaveTeamDisclaimer": "You are leaving the team {{ teamName }}. You will no longer have access to it.", - "deleteTeamErrorHeading": "Sorry, we couldn't delete your team.", - "leaveTeamErrorHeading": "Sorry, we couldn't leave your team.", - "searchMembersPlaceholder": "Search members", - "createTeamErrorHeading": "Sorry, we couldn't create your team.", - "createTeamErrorMessage": "We encountered an error creating your team. Please try again.", - "transferTeamErrorHeading": "Sorry, we couldn't transfer ownership of your team.", - "transferTeamErrorMessage": "We encountered an error transferring ownership of your team. Please try again.", - "updateRoleErrorHeading": "Sorry, we couldn't update the role of the selected member.", - "updateRoleErrorMessage": "We encountered an error updating the role of the selected member. Please try again.", + "dangerZoneSubheading": "Delete or leave your company", + "deleteTeam": "Delete Company", + "deleteTeamDescription": "This action cannot be undone. All data associated with this company will be deleted.", + "deletingTeam": "Deleting company", + "deleteTeamModalHeading": "Deleting Company", + "deletingTeamDescription": "You are about to delete the company {{ teamName }}. This action cannot be undone.", + "deleteTeamInputField": "Type the name of the company to confirm", + "leaveTeam": "Leave Company", + "leavingTeamModalHeading": "Leaving Company", + "leavingTeamModalDescription": "You are about to leave this company. You will no longer have access to it.", + "leaveTeamDescription": "Click the button below to leave the company. Remember, you will no longer have access to it and will need to be re-invited to join.", + "deleteTeamDisclaimer": "You are deleting the company {{ teamName }}. This action cannot be undone.", + "leaveTeamDisclaimer": "You are leaving the company {{ teamName }}. You will no longer have access to it.", + "deleteTeamErrorHeading": "Sorry, we couldn't delete your company.", + "leaveTeamErrorHeading": "Sorry, we couldn't leave your company.", + "searchMembersPlaceholder": "Search employees", + "createTeamErrorHeading": "Sorry, we couldn't create your company.", + "createTeamErrorMessage": "We encountered an error creating your company. Please try again.", + "transferTeamErrorHeading": "Sorry, we couldn't transfer ownership of your company account.", + "transferTeamErrorMessage": "We encountered an error transferring ownership of your company account. Please try again.", + "updateRoleErrorHeading": "Sorry, we couldn't update the role of the selected employee.", + "updateRoleErrorMessage": "We encountered an error updating the role of the selected employee. Please try again.", "searchInvitations": "Search Invitations", "updateInvitation": "Update Invitation", "removeInvitation": "Remove Invitation", @@ -144,20 +144,20 @@ "active": "Active", "inviteStatus": "Status", "inviteNotFoundOrExpired": "Invite not found or expired", - "inviteNotFoundOrExpiredDescription": "The invite you are looking for is either expired or does not exist. Please contact the team owner to renew the invite.", + "inviteNotFoundOrExpiredDescription": "The invite you are looking for is either expired or does not exist. Please contact the company HR to renew the invite.", "backToHome": "Back to Home", - "renewInvitationDialogDescription": "You are about to renew the invitation to {{ email }}. The user will be able to join the team.", + "renewInvitationDialogDescription": "You are about to renew the invitation to {{ email }}. The user will be able to join the company.", "renewInvitationErrorTitle": "Sorry, we couldn't renew the invitation.", "renewInvitationErrorDescription": "We encountered an error renewing the invitation. Please try again.", "signInWithDifferentAccount": "Sign in with a different account", "signInWithDifferentAccountDescription": "If you wish to accept the invitation with a different account, please sign out and back in with the account you wish to use.", "acceptInvitationHeading": "Accept Invitation to join {{accountName}}", - "acceptInvitationDescription": "You have been invited to join the team {{accountName}}. If you wish to accept the invitation, please click the button below.", + "acceptInvitationDescription": "You have been invited to join the company {{accountName}}. If you wish to accept the invitation, please click the button below.", "continueAs": "Continue as {{email}}", - "joinTeamAccount": "Join Team", - "joiningTeam": "Joining team...", - "leaveTeamInputLabel": "Please type LEAVE to confirm leaving the team.", - "leaveTeamInputDescription": "By leaving the team, you will no longer have access to it.", + "joinTeamAccount": "Join Company", + "joiningTeam": "Joining company...", + "leaveTeamInputLabel": "Please type LEAVE to confirm leaving the company.", + "leaveTeamInputDescription": "By leaving the company, you will no longer have access to it.", "reservedNameError": "This name is reserved. Please choose a different one.", "specialCharactersError": "This name cannot contain special characters. Please choose a different one." } diff --git a/public/locales/ru/auth.json b/public/locales/ru/auth.json index 3bb81d4..7db0925 100644 --- a/public/locales/ru/auth.json +++ b/public/locales/ru/auth.json @@ -63,8 +63,8 @@ "sendingEmailCode": "Sending code...", "resetPasswordError": "Sorry, we could not reset your password. Please try again.", "emailPlaceholder": "your@email.com", - "inviteAlertHeading": "You have been invited to join a team", - "inviteAlertBody": "Please sign in or sign up to accept the invite and join the team.", + "inviteAlertHeading": "You have been invited to join a company", + "inviteAlertBody": "Please sign in or sign up to accept the invite and join the company.", "acceptTermsAndConditions": "I accept the and ", "termsOfService": "Terms of Service", "privacyPolicy": "Privacy Policy", diff --git a/public/locales/ru/billing.json b/public/locales/ru/billing.json index 9efef35..84c849e 100644 --- a/public/locales/ru/billing.json +++ b/public/locales/ru/billing.json @@ -18,8 +18,8 @@ "checkoutSuccessBackButton": "Proceed to App", "cannotManageBillingAlertTitle": "You cannot manage billing", "cannotManageBillingAlertDescription": "You do not have permissions to manage billing. Please contact your account owner.", - "manageTeamPlan": "Manage your Team Plan", - "manageTeamPlanDescription": "Choose a plan that fits your team's needs. You can upgrade or downgrade your plan at any time.", + "manageTeamPlan": "Manage your Company Plan", + "manageTeamPlanDescription": "Choose a plan that fits your company's needs. You can upgrade or downgrade your plan at any time.", "basePlan": "Base Plan", "billingInterval": { "label": "Choose your billing interval", @@ -34,9 +34,9 @@ "redirectingToPayment": "Redirecting to checkout. Please wait...", "proceedToPayment": "Proceed to Payment", "startTrial": "Start Trial", - "perTeamMember": "Per team member", + "perTeamMember": "Per company employee", "perUnit": "Per {{unit}} usage", - "teamMembers": "Team Members", + "teamMembers": "Company Employees", "includedUpTo": "Up to {{upTo}} {{unit}} included in the plan", "fromPreviousTierUpTo": "for each {{unit}} for the next {{ upTo }} {{ unit }}", "andAbove": "above {{ previousTier }} {{ unit }}", diff --git a/public/locales/ru/common.json b/public/locales/ru/common.json index c194ce3..8aade69 100644 --- a/public/locales/ru/common.json +++ b/public/locales/ru/common.json @@ -1,8 +1,8 @@ { "homeTabLabel": "Home", "homeTabDescription": "Welcome to your home page", - "accountMembers": "Team Members", - "membersTabDescription": "Here you can manage the members of your team.", + "accountMembers": "Company Employees", + "membersTabDescription": "Here you can manage the employees of your company.", "billingTabLabel": "Billing", "billingTabDescription": "Manage your billing and subscription", "dashboardTabLabel": "Dashboard", @@ -58,7 +58,7 @@ "routes": { "home": "Home", "account": "Account", - "members": "Members", + "members": "Employees", "billing": "Billing", "dashboard": "Dashboard", "settings": "Settings", @@ -70,7 +70,7 @@ "label": "Owner" }, "member": { - "label": "Member" + "label": "Employee" } }, "otp": { diff --git a/public/locales/ru/marketing.json b/public/locales/ru/marketing.json index 50076c7..a214fc2 100644 --- a/public/locales/ru/marketing.json +++ b/public/locales/ru/marketing.json @@ -36,5 +36,5 @@ "contactErrorDescription": "An error occurred while sending your message. Please try again later", "footerDescription": "Here you can add a description about your company or product", "copyright": "© Copyright {{year}} {{product}}. All Rights Reserved.", - "heroSubtitle": "Простой, удобный и быстрый обзор вашего состояния здоровья" + "heroSubtitle": "A simple, convenient, and quick overview of your health condition" } diff --git a/public/locales/ru/teams.json b/public/locales/ru/teams.json index 2a0b614..d09d78d 100644 --- a/public/locales/ru/teams.json +++ b/public/locales/ru/teams.json @@ -4,26 +4,26 @@ }, "settings": { "pageTitle": "Settings", - "pageDescription": "Manage your Team details", - "teamLogo": "Team Logo", - "teamLogoDescription": "Update your team's logo to make it easier to identify", - "teamName": "Team Name", - "teamNameDescription": "Update your team's name", + "pageDescription": "Manage your Company details", + "teamLogo": "Company Logo", + "teamLogoDescription": "Update your company's logo to make it easier to identify", + "teamName": "Company Name", + "teamNameDescription": "Update your company's name", "dangerZone": "Danger Zone", "dangerZoneDescription": "This section contains actions that are irreversible" }, "members": { - "pageTitle": "Members" + "pageTitle": "Employees" }, "billing": { "pageTitle": "Billing" }, - "yourTeams": "Your Teams ({{teamsCount}})", - "createTeam": "Create a Team", - "creatingTeam": "Creating Team...", + "yourTeams": "Your Companies ({{teamsCount}})", + "createTeam": "Create a Company", + "creatingTeam": "Creating Company...", "personalAccount": "Personal Account", "searchAccount": "Search Account...", - "membersTabLabel": "Members", + "membersTabLabel": "Employees", "memberName": "Name", "youLabel": "You", "emailLabel": "Email", @@ -31,108 +31,108 @@ "primaryOwnerLabel": "Primary Owner", "joinedAtLabel": "Joined at", "invitedAtLabel": "Invited at", - "inviteMembersPageSubheading": "Invite members to your Team", - "createTeamModalHeading": "Create Team", - "createTeamModalDescription": "Create a new Team to manage your projects and members.", - "teamNameLabel": "Team Name", - "teamNameDescription": "Your team name should be unique and descriptive", - "createTeamSubmitLabel": "Create Team", - "createTeamSuccess": "Team created successfully", - "createTeamError": "Team not created. Please try again.", - "createTeamLoading": "Creating team...", + "inviteMembersPageSubheading": "Invite employees to your Company", + "createTeamModalHeading": "Create Company", + "createTeamModalDescription": "Create a new Company to manage your projects and employees.", + "teamNameLabel": "Company Name", + "teamNameDescription": "Your company name should be unique and descriptive", + "createTeamSubmitLabel": "Create Company", + "createTeamSuccess": "Company created successfully", + "createTeamError": "Company not created. Please try again.", + "createTeamLoading": "Creating company...", "settingsPageLabel": "General", - "createTeamDropdownLabel": "New team", + "createTeamDropdownLabel": "New company", "changeRole": "Change Role", "removeMember": "Remove from Account", - "inviteMembersSuccess": "Members invited successfully!", + "inviteMembersSuccess": "Employees invited successfully!", "inviteMembersError": "Sorry, we encountered an error! Please try again", - "inviteMembersLoading": "Inviting members...", + "inviteMembersLoading": "Inviting employees...", "removeInviteButtonLabel": "Remove invite", "addAnotherMemberButtonLabel": "Add another one", "inviteMembersButtonLabel": "Send Invites", "removeMemberModalHeading": "You are removing this user", - "removeMemberModalDescription": "Remove this member from the team. They will no longer have access to the team.", - "removeMemberSuccessMessage": "Member removed successfully", + "removeMemberModalDescription": "Remove this employee from the company. They will no longer have access to the company.", + "removeMemberSuccessMessage": "Employee removed successfully", "removeMemberErrorMessage": "Sorry, we encountered an error. Please try again", - "removeMemberErrorHeading": "Sorry, we couldn't remove the selected member.", - "removeMemberLoadingMessage": "Removing member...", - "removeMemberSubmitLabel": "Remove User from Team", + "removeMemberErrorHeading": "Sorry, we couldn't remove the selected employee.", + "removeMemberLoadingMessage": "Removing employee...", + "removeMemberSubmitLabel": "Remove User from Company", "chooseDifferentRoleError": "Role is the same as the current one", "updateRole": "Update Role", "updateRoleLoadingMessage": "Updating role...", "updateRoleSuccessMessage": "Role updated successfully", "updatingRoleErrorMessage": "Sorry, we encountered an error. Please try again.", - "updateMemberRoleModalHeading": "Update Member's Role", + "updateMemberRoleModalHeading": "Update Employee's Role", "updateMemberRoleModalDescription": "Change the role of the selected member. The role determines the permissions of the member.", "roleMustBeDifferent": "Role must be different from the current one", "memberRoleInputLabel": "Member role", "updateRoleDescription": "Pick a role for this member.", "updateRoleSubmitLabel": "Update Role", "transferOwnership": "Transfer Ownership", - "transferOwnershipDescription": "Transfer ownership of the team to another member.", + "transferOwnershipDescription": "Transfer ownership of the company account to another employee.", "transferOwnershipInputLabel": "Please type TRANSFER to confirm the transfer of ownership.", - "transferOwnershipInputDescription": "By transferring ownership, you will no longer be the primary owner of the team.", + "transferOwnershipInputDescription": "By transferring ownership, you will no longer be the primary owner of the company account.", "deleteInvitation": "Delete Invitation", - "deleteInvitationDialogDescription": "You are about to delete the invitation. The user will no longer be able to join the team.", + "deleteInvitationDialogDescription": "You are about to delete the invitation. The user will no longer be able to join the company account.", "deleteInviteSuccessMessage": "Invite deleted successfully", "deleteInviteErrorMessage": "Invite not deleted. Please try again.", "deleteInviteLoadingMessage": "Deleting invite. Please wait...", "confirmDeletingMemberInvite": "You are deleting the invite to {{ email }}", - "transferOwnershipDisclaimer": "You are transferring ownership of the selected team to {{ member }}.", + "transferOwnershipDisclaimer": "You are transferring ownership of the selected company account to {{ member }}.", "transferringOwnership": "Transferring ownership...", "transferOwnershipSuccess": "Ownership successfully transferred", "transferOwnershipError": "Sorry, we could not transfer ownership to the selected member. Please try again.", "deleteInviteSubmitLabel": "Delete Invite", "youBadgeLabel": "You", - "updateTeamLoadingMessage": "Updating Team...", - "updateTeamSuccessMessage": "Team successfully updated", - "updateTeamErrorMessage": "Could not update Team. Please try again.", + "updateTeamLoadingMessage": "Updating Company...", + "updateTeamSuccessMessage": "Company successfully updated", + "updateTeamErrorMessage": "Could not update Company. Please try again.", "updateLogoErrorMessage": "Could not update Logo. Please try again.", - "teamNameInputLabel": "Team Name", - "teamLogoInputHeading": "Upload your team's Logo", - "teamLogoInputSubheading": "Please choose a photo to upload as your team logo.", - "updateTeamSubmitLabel": "Update Team", - "inviteMembersHeading": "Invite Members to your Team", - "inviteMembersDescription": "Invite members to your team by entering their email and role.", - "emailPlaceholder": "member@email.com", - "membersPageHeading": "Members", - "inviteMembersButton": "Invite Members", - "invitingMembers": "Inviting members...", - "inviteMembersSuccessMessage": "Members invited successfully", - "inviteMembersErrorMessage": "Sorry, members could not be invited. Please try again.", + "teamNameInputLabel": "Company Name", + "teamLogoInputHeading": "Upload your company's Logo", + "teamLogoInputSubheading": "Please choose a photo to upload as your company logo.", + "updateTeamSubmitLabel": "Update Company", + "inviteMembersHeading": "Invite Employees to your Company", + "inviteMembersDescription": "Invite employees to your company by entering their email and role.", + "emailPlaceholder": "employee@email.com", + "membersPageHeading": "Employees", + "inviteMembersButton": "Invite Employees", + "invitingMembers": "Inviting employees...", + "inviteMembersSuccessMessage": "Employees invited successfully", + "inviteMembersErrorMessage": "Sorry, employees could not be invited. Please try again.", "pendingInvitesHeading": "Pending Invites", - "pendingInvitesDescription": " Here you can manage the pending invitations to your team.", + "pendingInvitesDescription": " Here you can manage the pending invitations to your company.", "noPendingInvites": "No pending invites found", - "loadingMembers": "Loading members...", - "loadMembersError": "Sorry, we couldn't fetch your team's members.", - "loadInvitedMembersError": "Sorry, we couldn't fetch your team's invited members.", - "loadingInvitedMembers": "Loading invited members...", + "loadingMembers": "Loading employees...", + "loadMembersError": "Sorry, we couldn't fetch your company's employees.", + "loadInvitedMembersError": "Sorry, we couldn't fetch your company's invited employees.", + "loadingInvitedMembers": "Loading invited employees...", "invitedBadge": "Invited", "duplicateInviteEmailError": "You have already entered this email address", "invitingOwnAccountError": "Hey, that's your email!", "dangerZone": "Danger Zone", - "dangerZoneSubheading": "Delete or leave your team", - "deleteTeam": "Delete Team", - "deleteTeamDescription": "This action cannot be undone. All data associated with this team will be deleted.", - "deletingTeam": "Deleting team", - "deleteTeamModalHeading": "Deleting Team", - "deletingTeamDescription": "You are about to delete the team {{ teamName }}. This action cannot be undone.", - "deleteTeamInputField": "Type the name of the team to confirm", - "leaveTeam": "Leave Team", - "leavingTeamModalHeading": "Leaving Team", - "leavingTeamModalDescription": "You are about to leave this team. You will no longer have access to it.", - "leaveTeamDescription": "Click the button below to leave the team. Remember, you will no longer have access to it and will need to be re-invited to join.", - "deleteTeamDisclaimer": "You are deleting the team {{ teamName }}. This action cannot be undone.", - "leaveTeamDisclaimer": "You are leaving the team {{ teamName }}. You will no longer have access to it.", - "deleteTeamErrorHeading": "Sorry, we couldn't delete your team.", - "leaveTeamErrorHeading": "Sorry, we couldn't leave your team.", - "searchMembersPlaceholder": "Search members", - "createTeamErrorHeading": "Sorry, we couldn't create your team.", - "createTeamErrorMessage": "We encountered an error creating your team. Please try again.", - "transferTeamErrorHeading": "Sorry, we couldn't transfer ownership of your team.", - "transferTeamErrorMessage": "We encountered an error transferring ownership of your team. Please try again.", - "updateRoleErrorHeading": "Sorry, we couldn't update the role of the selected member.", - "updateRoleErrorMessage": "We encountered an error updating the role of the selected member. Please try again.", + "dangerZoneSubheading": "Delete or leave your company", + "deleteTeam": "Delete Company", + "deleteTeamDescription": "This action cannot be undone. All data associated with this company will be deleted.", + "deletingTeam": "Deleting company", + "deleteTeamModalHeading": "Deleting Company", + "deletingTeamDescription": "You are about to delete the company {{ teamName }}. This action cannot be undone.", + "deleteTeamInputField": "Type the name of the company to confirm", + "leaveTeam": "Leave Company", + "leavingTeamModalHeading": "Leaving Company", + "leavingTeamModalDescription": "You are about to leave this company. You will no longer have access to it.", + "leaveTeamDescription": "Click the button below to leave the company. Remember, you will no longer have access to it and will need to be re-invited to join.", + "deleteTeamDisclaimer": "You are deleting the company {{ teamName }}. This action cannot be undone.", + "leaveTeamDisclaimer": "You are leaving the company {{ teamName }}. You will no longer have access to it.", + "deleteTeamErrorHeading": "Sorry, we couldn't delete your company.", + "leaveTeamErrorHeading": "Sorry, we couldn't leave your company.", + "searchMembersPlaceholder": "Search employees", + "createTeamErrorHeading": "Sorry, we couldn't create your company.", + "createTeamErrorMessage": "We encountered an error creating your company. Please try again.", + "transferTeamErrorHeading": "Sorry, we couldn't transfer ownership of your company account.", + "transferTeamErrorMessage": "We encountered an error transferring ownership of your company account. Please try again.", + "updateRoleErrorHeading": "Sorry, we couldn't update the role of the selected employee.", + "updateRoleErrorMessage": "We encountered an error updating the role of the selected employee. Please try again.", "searchInvitations": "Search Invitations", "updateInvitation": "Update Invitation", "removeInvitation": "Remove Invitation", @@ -144,20 +144,20 @@ "active": "Active", "inviteStatus": "Status", "inviteNotFoundOrExpired": "Invite not found or expired", - "inviteNotFoundOrExpiredDescription": "The invite you are looking for is either expired or does not exist. Please contact the team owner to renew the invite.", + "inviteNotFoundOrExpiredDescription": "The invite you are looking for is either expired or does not exist. Please contact the company HR to renew the invite.", "backToHome": "Back to Home", - "renewInvitationDialogDescription": "You are about to renew the invitation to {{ email }}. The user will be able to join the team.", + "renewInvitationDialogDescription": "You are about to renew the invitation to {{ email }}. The user will be able to join the company.", "renewInvitationErrorTitle": "Sorry, we couldn't renew the invitation.", "renewInvitationErrorDescription": "We encountered an error renewing the invitation. Please try again.", "signInWithDifferentAccount": "Sign in with a different account", "signInWithDifferentAccountDescription": "If you wish to accept the invitation with a different account, please sign out and back in with the account you wish to use.", "acceptInvitationHeading": "Accept Invitation to join {{accountName}}", - "acceptInvitationDescription": "You have been invited to join the team {{accountName}}. If you wish to accept the invitation, please click the button below.", + "acceptInvitationDescription": "You have been invited to join the company {{accountName}}. If you wish to accept the invitation, please click the button below.", "continueAs": "Continue as {{email}}", - "joinTeamAccount": "Join Team", - "joiningTeam": "Joining team...", - "leaveTeamInputLabel": "Please type LEAVE to confirm leaving the team.", - "leaveTeamInputDescription": "By leaving the team, you will no longer have access to it.", + "joinTeamAccount": "Join Company", + "joiningTeam": "Joining company...", + "leaveTeamInputLabel": "Please type LEAVE to confirm leaving the company.", + "leaveTeamInputDescription": "By leaving the company, you will no longer have access to it.", "reservedNameError": "This name is reserved. Please choose a different one.", "specialCharactersError": "This name cannot contain special characters. Please choose a different one." } From 6e83d25a8cc2229968ec2cc77627149c1821971a Mon Sep 17 00:00:00 2001 From: devmc-ee Date: Sun, 15 Jun 2025 12:45:55 +0300 Subject: [PATCH 3/6] B2B-30: add button to create company from super admin page --- app/admin/_components/admin-sidebar.tsx | 6 +- app/admin/accounts/page.tsx | 9 +- components/app-logo.tsx | 10 +- components/med-report-title.tsx | 6 +- .../admin-create-company-dialog.tsx | 144 ++++++++++++++++++ .../src/lib/server/admin-server-actions.ts | 38 +++++ .../server/schema/create-company.schema.ts | 53 +++++++ .../services/create-team-account.service.ts | 45 ++++++ 8 files changed, 301 insertions(+), 10 deletions(-) create mode 100644 packages/features/admin/src/components/admin-create-company-dialog.tsx create mode 100644 packages/features/admin/src/lib/server/schema/create-company.schema.ts create mode 100644 packages/features/admin/src/lib/server/services/create-team-account.service.ts diff --git a/app/admin/_components/admin-sidebar.tsx b/app/admin/_components/admin-sidebar.tsx index d7d655c..5b6c230 100644 --- a/app/admin/_components/admin-sidebar.tsx +++ b/app/admin/_components/admin-sidebar.tsx @@ -15,6 +15,7 @@ import { SidebarHeader, SidebarMenu, SidebarMenuButton, + useSidebar, } from '@kit/ui/shadcn-sidebar'; import { AppLogo } from '~/components/app-logo'; @@ -22,11 +23,12 @@ import { ProfileAccountDropdownContainer } from '~/components/personal-account-d export function AdminSidebar() { const path = usePathname(); + const { open } = useSidebar(); return ( - + @@ -64,4 +66,4 @@ export function AdminSidebar() { ); -} +} \ No newline at end of file diff --git a/app/admin/accounts/page.tsx b/app/admin/accounts/page.tsx index d83191b..21c1104 100644 --- a/app/admin/accounts/page.tsx +++ b/app/admin/accounts/page.tsx @@ -2,6 +2,7 @@ import { ServerDataLoader } from '@makerkit/data-loader-supabase-nextjs'; import { AdminAccountsTable } from '@kit/admin/components/admin-accounts-table'; import { AdminCreateUserDialog } from '@kit/admin/components/admin-create-user-dialog'; +import { AdminCreateCompanyDialog } from '@kit/admin/components/admin-create-company-dialog'; import { AdminGuard } from '@kit/admin/components/admin-guard'; import { getSupabaseServerClient } from '@kit/supabase/server-client'; import { AppBreadcrumbs } from '@kit/ui/app-breadcrumbs'; @@ -30,10 +31,14 @@ async function AccountsPage(props: AdminAccountsPageProps) { return ( <> }> -
+
- + + + + +
diff --git a/components/app-logo.tsx b/components/app-logo.tsx index c2fe283..d11f922 100644 --- a/components/app-logo.tsx +++ b/components/app-logo.tsx @@ -4,29 +4,33 @@ import { MedReportLogo } from './med-report-title'; function LogoImage({ className, + compact = false, }: { className?: string; width?: number; + compact?: boolean; }) { - return ; + return ; } export function AppLogo({ href, label, className, + compact = false, }: { href?: string | null; className?: string; label?: string; + compact?: boolean; }) { if (href === null) { - return ; + return ; } return ( - + ); } diff --git a/components/med-report-title.tsx b/components/med-report-title.tsx index bf809f8..efbea64 100644 --- a/components/med-report-title.tsx +++ b/components/med-report-title.tsx @@ -1,11 +1,11 @@ import { cn } from "@/lib/utils"; import { MedReportSmallLogo } from "@/public/assets/med-report-small-logo"; -export const MedReportLogo = ({ className }: { className?: string }) => ( +export const MedReportLogo = ({ className, compact = false }: { className?: string, compact?: boolean }) => (
- + {!compact && MedReport - + }
); diff --git a/packages/features/admin/src/components/admin-create-company-dialog.tsx b/packages/features/admin/src/components/admin-create-company-dialog.tsx new file mode 100644 index 0000000..3dacfed --- /dev/null +++ b/packages/features/admin/src/components/admin-create-company-dialog.tsx @@ -0,0 +1,144 @@ +'use client'; + +import { useState, useTransition } from 'react'; + +import { zodResolver } from '@hookform/resolvers/zod'; +import { useForm } from 'react-hook-form'; + +import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert'; +import { + AlertDialog, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from '@kit/ui/alert-dialog'; +import { Button } from '@kit/ui/button'; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@kit/ui/form'; +import { If } from '@kit/ui/if'; +import { Input } from '@kit/ui/input'; +import { toast } from '@kit/ui/sonner'; + +import { createTeamAccountAction } from '../lib/server/admin-server-actions'; +import { CreateCompanySchema, CreateCompanySchemaType } from '../lib/server/schema/create-company.schema'; +import { Trans } from '@kit/ui/trans'; + +export function AdminCreateCompanyDialog(props: React.PropsWithChildren) { + const [pending, startTransition] = useTransition(); + const [error, setError] = useState(null); + const [open, setOpen] = useState(false); + + const form = useForm({ + resolver: zodResolver(CreateCompanySchema), + defaultValues: { + name: '', + }, + mode: 'onChange', + }); + + const onSubmit = (data: CreateCompanySchemaType) => { + startTransition(async () => { + try { + const error = await createTeamAccountAction(data); + + if (!error) { + toast.success('Company creates successfully'); + form.reset(); + + setOpen(false); + setError(null); + + + } else { + setError('Something went wrong with company creation'); + + } + + + } catch (e) { + setError(e instanceof Error ? e.message : 'Error'); + } + }); + }; + + return ( + + {props.children} + + + + Create New Company Account + + + Complete the form below to create a new company account. + + + +
+ + + + Error + + {error} + + + + { + return ( + + + + + + + + + + + + + + + + ); + }} + /> + + + Cancel + + + + + +
+
+ ); +} diff --git a/packages/features/admin/src/lib/server/admin-server-actions.ts b/packages/features/admin/src/lib/server/admin-server-actions.ts index 260724f..060980d 100644 --- a/packages/features/admin/src/lib/server/admin-server-actions.ts +++ b/packages/features/admin/src/lib/server/admin-server-actions.ts @@ -20,6 +20,8 @@ import { ResetPasswordSchema } from './schema/reset-password.schema'; import { createAdminAccountsService } from './services/admin-accounts.service'; import { createAdminAuthUserService } from './services/admin-auth-user.service'; import { adminAction } from './utils/admin-action'; +import { CreateCompanySchema } from './schema/create-company.schema'; +import { createCreateTeamAccountService } from './services/create-team-account.service'; /** * @name banUserAction @@ -222,6 +224,42 @@ export const resetPasswordAction = adminAction( ), ); +export const createTeamAccountAction = enhanceAction( + async ({ name }, user) => { + const logger = await getLogger(); + const client = getSupabaseServerClient(); + const service = createCreateTeamAccountService(client); + + const ctx = { + name: 'team-accounts.create', + userId: user.id, + accountName: name, + }; + + logger.info(ctx, `Creating company account...`); + + const { data, error } = await service.createNewOrganizationAccount({ + name, + userId: user.id, + }); + + if (error) { + logger.error({ ...ctx, error }, `Failed to create company account`); + + return { + error: true, + }; + } + + logger.info(ctx, `Company account created`); + + redirect(`/home/${data.slug}/settings`); + }, + { + schema: CreateCompanySchema, + }, +); + function revalidateAdmin() { revalidatePath('/admin', 'layout'); } diff --git a/packages/features/admin/src/lib/server/schema/create-company.schema.ts b/packages/features/admin/src/lib/server/schema/create-company.schema.ts new file mode 100644 index 0000000..26daa01 --- /dev/null +++ b/packages/features/admin/src/lib/server/schema/create-company.schema.ts @@ -0,0 +1,53 @@ +import { z } from 'zod'; + +/** + * @name RESERVED_NAMES_ARRAY + * @description Array of reserved names for team accounts + * This is a list of names that cannot be used for team accounts as they are reserved for other purposes. + * Please include any new reserved names here. + */ +const RESERVED_NAMES_ARRAY = [ + 'settings', + 'billing', + // please add more reserved names here +]; + +const SPECIAL_CHARACTERS_REGEX = /[!@#$%^&*()+=[\]{};':"\\|,.<>/?]/; + +/** + * @name CompanyNameSchema + */ +export const CompanyNameSchema = z + .string({ + description: 'The name of the company account', + }) + .min(2) + .max(50) + .refine( + (name) => { + console.log(name); + return !SPECIAL_CHARACTERS_REGEX.test(name); + }, + { + message: 'teams:specialCharactersError', + }, + ) + .refine( + (name) => { + return !RESERVED_NAMES_ARRAY.includes(name.toLowerCase()); + }, + { + message: 'teams:reservedNameError', + }, + ); + +/** + * @name CreateCompanySchema + * @description Schema for creating a team account + */ +export const CreateCompanySchema = z.object({ + name: CompanyNameSchema, +}); + +export type CreateCompanySchemaType = z.infer; + diff --git a/packages/features/admin/src/lib/server/services/create-team-account.service.ts b/packages/features/admin/src/lib/server/services/create-team-account.service.ts new file mode 100644 index 0000000..0a0edea --- /dev/null +++ b/packages/features/admin/src/lib/server/services/create-team-account.service.ts @@ -0,0 +1,45 @@ +import 'server-only'; + +import { SupabaseClient } from '@supabase/supabase-js'; + +import { getLogger } from '@kit/shared/logger'; +import { Database } from '@kit/supabase/database'; + +export function createCreateTeamAccountService( + client: SupabaseClient, +) { + return new CreateTeamAccountService(client); +} + +class CreateTeamAccountService { + private readonly namespace = 'accounts.create-team-account'; + + constructor(private readonly client: SupabaseClient) {} + + async createNewOrganizationAccount(params: { name: string; userId: string }) { + const logger = await getLogger(); + const ctx = { ...params, namespace: this.namespace }; + + logger.info(ctx, `Creating new company account...`); + + const { error, data } = await this.client.rpc('create_team_account', { + account_name: params.name, + }); + + if (error) { + logger.error( + { + error, + ...ctx, + }, + `Error creating company account`, + ); + + throw new Error('Error creating company account'); + } + + logger.info(ctx, `Company account created successfully`); + + return { data, error }; + } +} From c41bf7aa3af47d38503a2c3f7abfb4ba96cfc2ca Mon Sep 17 00:00:00 2001 From: devmc-ee Date: Sun, 15 Jun 2025 12:56:59 +0300 Subject: [PATCH 4/6] B2B-30: minor fixes, renamings --- .../admin/src/components/admin-create-company-dialog.tsx | 4 ++-- .../features/admin/src/lib/server/admin-server-actions.ts | 6 +++--- ...t.service.ts => admin-create-company-account.service.ts} | 2 +- supabase/config.toml | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) rename packages/features/admin/src/lib/server/services/{create-team-account.service.ts => admin-create-company-account.service.ts} (95%) diff --git a/packages/features/admin/src/components/admin-create-company-dialog.tsx b/packages/features/admin/src/components/admin-create-company-dialog.tsx index 3dacfed..8cc06f4 100644 --- a/packages/features/admin/src/components/admin-create-company-dialog.tsx +++ b/packages/features/admin/src/components/admin-create-company-dialog.tsx @@ -30,7 +30,7 @@ import { If } from '@kit/ui/if'; import { Input } from '@kit/ui/input'; import { toast } from '@kit/ui/sonner'; -import { createTeamAccountAction } from '../lib/server/admin-server-actions'; +import { createCompanyAccountAction } from '../lib/server/admin-server-actions'; import { CreateCompanySchema, CreateCompanySchemaType } from '../lib/server/schema/create-company.schema'; import { Trans } from '@kit/ui/trans'; @@ -50,7 +50,7 @@ export function AdminCreateCompanyDialog(props: React.PropsWithChildren) { const onSubmit = (data: CreateCompanySchemaType) => { startTransition(async () => { try { - const error = await createTeamAccountAction(data); + const error = await createCompanyAccountAction(data); if (!error) { toast.success('Company creates successfully'); diff --git a/packages/features/admin/src/lib/server/admin-server-actions.ts b/packages/features/admin/src/lib/server/admin-server-actions.ts index 060980d..cac9ae9 100644 --- a/packages/features/admin/src/lib/server/admin-server-actions.ts +++ b/packages/features/admin/src/lib/server/admin-server-actions.ts @@ -21,7 +21,7 @@ import { createAdminAccountsService } from './services/admin-accounts.service'; import { createAdminAuthUserService } from './services/admin-auth-user.service'; import { adminAction } from './utils/admin-action'; import { CreateCompanySchema } from './schema/create-company.schema'; -import { createCreateTeamAccountService } from './services/create-team-account.service'; +import { createCreateCompanyAccountService } from './services/admin-create-company-account.service'; /** * @name banUserAction @@ -224,11 +224,11 @@ export const resetPasswordAction = adminAction( ), ); -export const createTeamAccountAction = enhanceAction( +export const createCompanyAccountAction = enhanceAction( async ({ name }, user) => { const logger = await getLogger(); const client = getSupabaseServerClient(); - const service = createCreateTeamAccountService(client); + const service = createCreateCompanyAccountService(client); const ctx = { name: 'team-accounts.create', diff --git a/packages/features/admin/src/lib/server/services/create-team-account.service.ts b/packages/features/admin/src/lib/server/services/admin-create-company-account.service.ts similarity index 95% rename from packages/features/admin/src/lib/server/services/create-team-account.service.ts rename to packages/features/admin/src/lib/server/services/admin-create-company-account.service.ts index 0a0edea..db59f34 100644 --- a/packages/features/admin/src/lib/server/services/create-team-account.service.ts +++ b/packages/features/admin/src/lib/server/services/admin-create-company-account.service.ts @@ -5,7 +5,7 @@ import { SupabaseClient } from '@supabase/supabase-js'; import { getLogger } from '@kit/shared/logger'; import { Database } from '@kit/supabase/database'; -export function createCreateTeamAccountService( +export function createCreateCompanyAccountService( client: SupabaseClient, ) { return new CreateTeamAccountService(client); diff --git a/supabase/config.toml b/supabase/config.toml index a5fe81f..0e17285 100644 --- a/supabase/config.toml +++ b/supabase/config.toml @@ -82,7 +82,7 @@ port = 54324 # Uncomment to expose additional ports for testing user applications that send emails. # smtp_port = 54325 # pop3_port = 54326 -# admin_email = "info@devmc.ee" +# admin_email = "" # sender_name = "Admin" [storage] From 6b884d0dd951f7ccc74d84d3df9c0a2f6c1aa61a Mon Sep 17 00:00:00 2001 From: devmc-ee Date: Sun, 15 Jun 2025 13:06:27 +0300 Subject: [PATCH 5/6] B2B-30: fix redirect target after company creation --- .../src/server/actions/create-team-account-server-actions.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/features/team-accounts/src/server/actions/create-team-account-server-actions.ts b/packages/features/team-accounts/src/server/actions/create-team-account-server-actions.ts index a741c20..1783688 100644 --- a/packages/features/team-accounts/src/server/actions/create-team-account-server-actions.ts +++ b/packages/features/team-accounts/src/server/actions/create-team-account-server-actions.ts @@ -38,9 +38,7 @@ export const createTeamAccountAction = enhanceAction( logger.info(ctx, `Team account created`); - const accountHomePath = '/home/' + data.slug; - - redirect(accountHomePath); + redirect(`/home/${data.slug}/settings`); }, { schema: CreateTeamSchema, From 39c02c6d3442f43467d4350ab584a01556239c32 Mon Sep 17 00:00:00 2001 From: devmc-ee Date: Mon, 16 Jun 2025 09:00:27 +0300 Subject: [PATCH 6/6] B2B-30: fix typos, remove debug console --- .../admin/src/components/admin-create-company-dialog.tsx | 2 +- .../features/admin/src/components/admin-create-user-dialog.tsx | 2 +- .../admin/src/lib/server/schema/create-company.schema.ts | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/features/admin/src/components/admin-create-company-dialog.tsx b/packages/features/admin/src/components/admin-create-company-dialog.tsx index 8cc06f4..54d14e9 100644 --- a/packages/features/admin/src/components/admin-create-company-dialog.tsx +++ b/packages/features/admin/src/components/admin-create-company-dialog.tsx @@ -53,7 +53,7 @@ export function AdminCreateCompanyDialog(props: React.PropsWithChildren) { const error = await createCompanyAccountAction(data); if (!error) { - toast.success('Company creates successfully'); + toast.success('Company created successfully'); form.reset(); setOpen(false); diff --git a/packages/features/admin/src/components/admin-create-user-dialog.tsx b/packages/features/admin/src/components/admin-create-user-dialog.tsx index cb5105e..bc21c4a 100644 --- a/packages/features/admin/src/components/admin-create-user-dialog.tsx +++ b/packages/features/admin/src/components/admin-create-user-dialog.tsx @@ -58,7 +58,7 @@ export function AdminCreateUserDialog(props: React.PropsWithChildren) { const result = await createUserAction(data); if (result.success) { - toast.success('User creates successfully'); + toast.success('User created successfully'); form.reset(); setOpen(false); diff --git a/packages/features/admin/src/lib/server/schema/create-company.schema.ts b/packages/features/admin/src/lib/server/schema/create-company.schema.ts index 26daa01..4fc0a04 100644 --- a/packages/features/admin/src/lib/server/schema/create-company.schema.ts +++ b/packages/features/admin/src/lib/server/schema/create-company.schema.ts @@ -25,7 +25,6 @@ export const CompanyNameSchema = z .max(50) .refine( (name) => { - console.log(name); return !SPECIAL_CHARACTERS_REGEX.test(name); }, {