feat: migrate auth from supabase to better auth (#596)
* feat: add README for @cio/db package and remove existingAccounts.json * load session, load profile and organization, add create profile hook * chore: cache session request The trick was passing all the cookies to the backend. Previously I was only passing the better-auth.session_token and not better-auth.session_data. Read about the difference here https://www.better-auth.com/docs/concepts/cookies#custom-cookies * feat: login, logout, onboarding, verify email, reset password. * feat: complete change email and email verification * feat: standardise how we make rpc calls and create org endpoints * fix ui errors * fix: handle potential undefined customerId and standardize avatar URL property * refactor: standardize custom domain handling and update telegram chat ID references * chore: add tailwind prefix to @cio/ui this fixed the media query issues because @cio/ui classes were overriding this dashboard tailwind build * chore: clean up org sidebar * chore: persist mode state * feat: implement order breadcrumbs * chore: upgrade to better auth 1.4 * chore: address common auth flow bugs and setup app for others to setup locally.
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
export * from './roles';
|
||||
export * from './org';
|
||||
@@ -0,0 +1,34 @@
|
||||
export const blockedSubdomain = [
|
||||
'academy',
|
||||
'app',
|
||||
'apps',
|
||||
'blog',
|
||||
'build',
|
||||
'campaign',
|
||||
'church',
|
||||
'cloud',
|
||||
'community',
|
||||
'conference',
|
||||
'course',
|
||||
'courses',
|
||||
'demo',
|
||||
'dev',
|
||||
'forum',
|
||||
'group',
|
||||
'groups',
|
||||
'help',
|
||||
'launch',
|
||||
'launchweek',
|
||||
'mobile',
|
||||
'play',
|
||||
'prod',
|
||||
'production',
|
||||
'schools',
|
||||
'stage',
|
||||
'staging',
|
||||
'support',
|
||||
'teacher',
|
||||
'teachers',
|
||||
'tech',
|
||||
'training'
|
||||
];
|
||||
@@ -0,0 +1,5 @@
|
||||
export const ROLE = {
|
||||
ADMIN: 1,
|
||||
TUTOR: 2,
|
||||
STUDENT: 3
|
||||
} as const;
|
||||
@@ -0,0 +1,5 @@
|
||||
// Main entry point for @cio/utils package
|
||||
export * from './plans';
|
||||
export * from './senja';
|
||||
export * from './validation';
|
||||
export * from './constants';
|
||||
@@ -7,8 +7,8 @@ export const PLAN = {
|
||||
export const PLAN_NAMES = {
|
||||
[PLAN.BASIC]: 'Free',
|
||||
[PLAN.EARLY_ADOPTER]: 'Early Adopter',
|
||||
[PLAN.ENTERPRISE]: 'Enterprise',
|
||||
}
|
||||
[PLAN.ENTERPRISE]: 'Enterprise'
|
||||
};
|
||||
|
||||
export const FEATURES = {
|
||||
BACIC_STUDENTS_50: 'BACIC_STUDENTS_50',
|
||||
|
||||
@@ -60,12 +60,7 @@
|
||||
"YEARLY": "Request Pricing",
|
||||
"IS_PREMIUM": true
|
||||
},
|
||||
"FEATURES": [
|
||||
"Everything in Early Adopters plus:",
|
||||
"Unlimited students",
|
||||
"Custom Domain",
|
||||
"24/7 Support"
|
||||
],
|
||||
"FEATURES": ["Everything in Early Adopters plus:", "Unlimited students", "Custom Domain", "24/7 Support"],
|
||||
"CTA": {
|
||||
"LABEL": "Contact Us",
|
||||
"LINK": "https://cal.com/classroomio/enterprise",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * from './constants';
|
||||
export * from './utils';
|
||||
|
||||
import * as PLANS from './data.json';
|
||||
import PLANS from './data.json';
|
||||
|
||||
export { PLANS };
|
||||
|
||||
@@ -0,0 +1,356 @@
|
||||
# Validation Schemas
|
||||
|
||||
Shared validation schemas for ClassroomIO workspace using Zod with **convention-based translations**.
|
||||
|
||||
## Structure
|
||||
|
||||
Each entity has its own folder with entity-specific schemas:
|
||||
|
||||
```
|
||||
validation/
|
||||
├── course/
|
||||
│ ├── course.ts # Course validation schemas
|
||||
│ └── index.ts # Re-exports
|
||||
├── mail/
|
||||
│ ├── mail.ts # Email validation schemas
|
||||
│ └── index.ts # Re-exports
|
||||
├── constants.ts # Shared constants
|
||||
├── index.ts # Main entry point
|
||||
├── README.md # This file
|
||||
└── USAGE.md # Detailed usage guide
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Import Schemas
|
||||
|
||||
```typescript
|
||||
// Import from main module
|
||||
import { ZCourseClone, TCourseClone } from '@cio/utils/validation';
|
||||
|
||||
// Import from entity module
|
||||
import { ZEmailData } from '@cio/utils/validation/mail';
|
||||
```
|
||||
|
||||
### Backend Usage (API)
|
||||
|
||||
Schemas are used **without custom error messages** - just validation rules:
|
||||
|
||||
```typescript
|
||||
import { ZCourseClone } from '@cio/utils/validation';
|
||||
import { zValidator } from '@hono/zod-validator';
|
||||
|
||||
export const cloneRouter = new Hono()
|
||||
.post('/', zValidator('json', ZCourseClone), async (c) => {
|
||||
const data = c.req.valid('json'); // Fully typed!
|
||||
// ... handle validated data
|
||||
});
|
||||
```
|
||||
|
||||
### Frontend Usage (Dashboard)
|
||||
|
||||
Use the error mapper to get translated messages:
|
||||
|
||||
```typescript
|
||||
import { ZEmailData } from '@cio/utils/validation/mail';
|
||||
import { mapZodErrorsToTranslations } from '$lib/utils/validation';
|
||||
|
||||
let formData = { to: '', subject: '', content: '' };
|
||||
let errors: Record<string, string> = {};
|
||||
|
||||
function handleSubmit() {
|
||||
const result = ZEmailData.safeParse(formData);
|
||||
|
||||
if (!result.success) {
|
||||
// Automatically maps to translations using convention
|
||||
errors = mapZodErrorsToTranslations(result.error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Use validated data
|
||||
doSomething(result.data);
|
||||
}
|
||||
```
|
||||
|
||||
## Translation Convention
|
||||
|
||||
We use **convention-based translation keys** to avoid hardcoding messages in schemas.
|
||||
|
||||
### How It Works
|
||||
|
||||
Schemas are clean with **no custom error messages**:
|
||||
|
||||
```typescript
|
||||
// ✅ Clean schema (in @cio/utils)
|
||||
export const ZEmailData = z.object({
|
||||
to: z.string().email(), // No message
|
||||
subject: z.string().min(1), // No message
|
||||
content: z.string().min(10) // No message
|
||||
});
|
||||
```
|
||||
|
||||
Frontend maps errors to translations using this convention:
|
||||
|
||||
```
|
||||
validations.{fieldName}.{errorCode}
|
||||
```
|
||||
|
||||
### Example Translation Keys
|
||||
|
||||
| Field | Validation | Error Code | Translation Key |
|
||||
|-------|-----------|------------|-----------------|
|
||||
| `to` | `.email()` | `invalid_string` | `validations.to.invalid_email` |
|
||||
| `subject` | `.min(1)` | `too_small` | `validations.subject.too_small` |
|
||||
| `username` | `.min(3)` | `too_small` | `validations.username.too_small` |
|
||||
| `username` | `.max(20)` | `too_big` | `validations.username.too_big` |
|
||||
|
||||
### Translation File Example
|
||||
|
||||
```json
|
||||
{
|
||||
"validations": {
|
||||
"to": {
|
||||
"invalid_email": "Invalid email address",
|
||||
"invalid_type": "Email is required"
|
||||
},
|
||||
"subject": {
|
||||
"too_small": "Subject is required"
|
||||
},
|
||||
"username": {
|
||||
"too_small": "Username must be at least 3 characters",
|
||||
"too_big": "Username cannot exceed 20 characters"
|
||||
},
|
||||
"generic": {
|
||||
"required": "This field is required",
|
||||
"invalid_email": "Invalid email address",
|
||||
"too_small_string": "Must be at least {min} characters"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Benefits
|
||||
|
||||
✅ **Single Source of Truth** - Schema defined once, used everywhere
|
||||
✅ **No Duplication** - Don't reimplement schemas in frontend
|
||||
✅ **Flexible** - Add specific translations or use generic fallbacks
|
||||
✅ **Multilingual** - Easy to translate without touching schemas
|
||||
✅ **Maintainable** - Change schema once, translations adapt automatically
|
||||
|
||||
### Common Error Codes
|
||||
|
||||
| Zod Error | When It Occurs |
|
||||
|-----------|----------------|
|
||||
| `too_small` | String too short, number too small, array too few items |
|
||||
| `too_big` | String too long, number too large, array too many items |
|
||||
| `invalid_email` | Invalid email format (from `.email()`) |
|
||||
| `invalid_url` | Invalid URL format (from `.url()`) |
|
||||
| `invalid_type` | Wrong type (e.g., undefined when string expected) |
|
||||
| `invalid_enum_value` | Value not in allowed options |
|
||||
|
||||
## Naming Convention
|
||||
|
||||
- **Schemas**: Prefixed with `Z` (e.g., `ZCourseClone`)
|
||||
- **Types**: Prefixed with `T` (e.g., `TCourseClone`)
|
||||
- **Translation Keys**: Follow pattern `validations.{field}.{errorCode}`
|
||||
|
||||
## Adding New Validations
|
||||
|
||||
### 1. Create Schema in Utils Package
|
||||
|
||||
```typescript
|
||||
// packages/utils/src/validation/lesson/lesson.ts
|
||||
import { z } from 'zod';
|
||||
|
||||
/**
|
||||
* Lesson Create Validation Schema
|
||||
* Used for creating new lessons
|
||||
*
|
||||
* Translation keys:
|
||||
* - validations.title.too_small
|
||||
* - validations.duration.too_small
|
||||
*/
|
||||
export const ZLessonCreate = z.object({
|
||||
title: z.string().min(1), // Clean - no message
|
||||
duration: z.number().min(1) // Clean - no message
|
||||
});
|
||||
export type TLessonCreate = z.infer<typeof ZLessonCreate>;
|
||||
|
||||
// validation/lesson/index.ts
|
||||
export * from './lesson';
|
||||
```
|
||||
|
||||
### 2. Export from Main Module
|
||||
|
||||
```typescript
|
||||
// packages/utils/src/validation/index.ts
|
||||
export * from './course';
|
||||
export * from './mail';
|
||||
export * from './lesson'; // Add this
|
||||
```
|
||||
|
||||
### 3. Use in API
|
||||
|
||||
```typescript
|
||||
// apps/api/src/routes/lesson/create.ts
|
||||
import { ZLessonCreate } from '@cio/utils/validation/lesson';
|
||||
import { zValidator } from '@hono/zod-validator';
|
||||
|
||||
export const lessonRouter = new Hono()
|
||||
.post('/', zValidator('json', ZLessonCreate), async (c) => {
|
||||
const data = c.req.valid('json');
|
||||
// ... create lesson
|
||||
});
|
||||
```
|
||||
|
||||
### 4. Add Translations in Frontend
|
||||
|
||||
```json
|
||||
// apps/dashboard/src/lib/utils/translations/en.json
|
||||
{
|
||||
"validations": {
|
||||
"title": {
|
||||
"too_small": "Title is required",
|
||||
"too_big": "Title is too long"
|
||||
},
|
||||
"duration": {
|
||||
"too_small": "Duration must be at least 1 minute"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Use in Frontend Form
|
||||
|
||||
```typescript
|
||||
// apps/dashboard/src/lib/components/LessonForm.svelte
|
||||
import { ZLessonCreate } from '@cio/utils/validation/lesson';
|
||||
import { mapZodErrorsToTranslations } from '$lib/utils/validation';
|
||||
|
||||
let formData = { title: '', duration: 0 };
|
||||
let errors = {};
|
||||
|
||||
function handleSubmit() {
|
||||
const result = ZLessonCreate.safeParse(formData);
|
||||
|
||||
if (!result.success) {
|
||||
errors = mapZodErrorsToTranslations(result.error);
|
||||
// errors.title = "Title is required" (translated)
|
||||
return;
|
||||
}
|
||||
|
||||
createLesson(result.data);
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Keep Schemas Clean - No Error Messages
|
||||
|
||||
Schemas should contain **only validation rules**, no custom messages:
|
||||
|
||||
```typescript
|
||||
// ✅ Good - Clean schema
|
||||
export const ZUserProfile = z.object({
|
||||
email: z.string().email(),
|
||||
username: z.string().min(3).max(20)
|
||||
});
|
||||
|
||||
// ❌ Bad - Hardcoded messages
|
||||
export const ZUserProfile = z.object({
|
||||
email: z.string().email('Invalid email'), // Don't do this
|
||||
username: z.string().min(3, 'Too short') // Don't do this
|
||||
});
|
||||
|
||||
// ❌ Bad - Translated messages in schema
|
||||
export const ZUserProfile = z.object({
|
||||
email: z.string().email(t.get('validations.email')) // Don't do this
|
||||
});
|
||||
```
|
||||
|
||||
**Why?** Schemas are shared between backend (no translations) and frontend (with translations). Keep them clean and universal.
|
||||
|
||||
### 2. Always Export Types
|
||||
|
||||
```typescript
|
||||
export const ZCourseClone = z.object({ /* ... */ });
|
||||
export type TCourseClone = z.infer<typeof ZCourseClone>;
|
||||
```
|
||||
|
||||
### 3. Document Schemas with Translation Keys
|
||||
|
||||
Help frontend developers know which translation keys to add:
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* User Profile Validation Schema
|
||||
* Used for updating user profile information
|
||||
*
|
||||
* Translation keys (convention-based):
|
||||
* - validations.email.invalid_email
|
||||
* - validations.username.too_small
|
||||
* - validations.username.too_big
|
||||
* - validations.bio.too_big
|
||||
*/
|
||||
export const ZUserProfile = z.object({
|
||||
email: z.string().email(),
|
||||
username: z.string().min(3).max(20),
|
||||
bio: z.string().max(500).optional()
|
||||
});
|
||||
export type TUserProfile = z.infer<typeof ZUserProfile>;
|
||||
```
|
||||
|
||||
### 4. Use Descriptive Field Names
|
||||
|
||||
Field names become part of translation keys, so use clear names:
|
||||
|
||||
```typescript
|
||||
// ✅ Good - Clear field names
|
||||
z.object({
|
||||
email: z.string().email(),
|
||||
fullName: z.string().min(5),
|
||||
phoneNumber: z.string().min(10)
|
||||
});
|
||||
// Translation keys: validations.email.*, validations.fullName.*, validations.phoneNumber.*
|
||||
|
||||
// ❌ Bad - Unclear field names
|
||||
z.object({
|
||||
e: z.string().email(),
|
||||
fn: z.string().min(5),
|
||||
ph: z.string().min(10)
|
||||
});
|
||||
// Translation keys: validations.e.*, validations.fn.*, validations.ph.* (unclear!)
|
||||
```
|
||||
|
||||
### 5. Group Related Validations
|
||||
|
||||
Keep related schemas together in the same entity folder:
|
||||
|
||||
```typescript
|
||||
// validation/user/user.ts
|
||||
export const ZUserCreate = z.object({ /* ... */ });
|
||||
export const ZUserUpdate = z.object({ /* ... */ });
|
||||
export const ZUserProfile = z.object({ /* ... */ });
|
||||
```
|
||||
|
||||
### 6. Don't Duplicate Schemas
|
||||
|
||||
**Never** reimplement schemas in the frontend:
|
||||
|
||||
```typescript
|
||||
// ❌ Bad - Reimplementing in frontend
|
||||
// apps/dashboard/src/schemas/user.ts
|
||||
export const userSchema = z.object({
|
||||
email: z.string().email(t.get('validations.email.invalid')),
|
||||
// ... duplicating from @cio/utils
|
||||
});
|
||||
|
||||
// ✅ Good - Import and use error mapper
|
||||
import { ZUserProfile } from '@cio/utils/validation/user';
|
||||
import { mapZodErrorsToTranslations } from '$lib/utils/validation';
|
||||
|
||||
const result = ZUserProfile.safeParse(data);
|
||||
if (!result.success) {
|
||||
errors = mapZodErrorsToTranslations(result.error);
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,25 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const ZUpdateProfile = z.object({
|
||||
fullname: z.string().min(5).optional(),
|
||||
username: z.string().min(5).optional(),
|
||||
locale: z.enum(['en', 'hi', 'fr', 'pt', 'de', 'vi', 'ru', 'es', 'pl', 'da']).optional(),
|
||||
avatarUrl: z.url().optional()
|
||||
});
|
||||
|
||||
export type TUpdateProfile = z.infer<typeof ZUpdateProfile>;
|
||||
|
||||
// Form validation schema - requires fullname and username
|
||||
export const ZProfileUpdateForm = ZUpdateProfile.extend({
|
||||
fullname: z.string().min(5),
|
||||
username: z.string().min(1)
|
||||
});
|
||||
|
||||
export type TProfileUpdateForm = z.infer<typeof ZProfileUpdateForm>;
|
||||
|
||||
// Email change validation schema
|
||||
export const ZChangeEmail = z.object({
|
||||
newEmail: z.email()
|
||||
});
|
||||
|
||||
export type TChangeEmail = z.infer<typeof ZChangeEmail>;
|
||||
@@ -0,0 +1 @@
|
||||
export * from './account';
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Validation Constants
|
||||
*
|
||||
* Shared constants used across validation schemas.
|
||||
* These should match the constants in the API.
|
||||
*/
|
||||
|
||||
export const ALLOWED_CONTENT_TYPES = ['video/mp4', 'video/quicktime', 'video/x-msvideo', 'video/x-matroska'] as const;
|
||||
|
||||
export const ALLOWED_DOCUMENT_TYPES = [
|
||||
'application/pdf',
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx
|
||||
'application/msword' // .doc
|
||||
] as const;
|
||||
@@ -0,0 +1,67 @@
|
||||
import { ALLOWED_CONTENT_TYPES, ALLOWED_DOCUMENT_TYPES } from '../constants';
|
||||
|
||||
import { z } from 'zod';
|
||||
|
||||
export const ZCourseClone = z.object({
|
||||
id: z.string().min(1),
|
||||
title: z.string().min(1),
|
||||
description: z.string().optional(),
|
||||
slug: z.string().min(1),
|
||||
organizationId: z.string().min(1)
|
||||
});
|
||||
export type TCourseClone = z.infer<typeof ZCourseClone>;
|
||||
|
||||
export const ZCertificateDownload = z.object({
|
||||
theme: z.string().min(1),
|
||||
studentName: z.string().min(1),
|
||||
courseName: z.string().min(1),
|
||||
courseDescription: z.string().min(1),
|
||||
orgName: z.string().min(1),
|
||||
orgLogoUrl: z.string().url().optional(),
|
||||
facilitator: z.string().optional()
|
||||
});
|
||||
export type TCertificateDownload = z.infer<typeof ZCertificateDownload>;
|
||||
|
||||
export const ZCourseDownloadContent = z.object({
|
||||
courseTitle: z.string().min(1),
|
||||
orgName: z.string().min(1),
|
||||
orgTheme: z.string().min(1),
|
||||
lessons: z.array(
|
||||
z.object({
|
||||
lessonTitle: z.string().min(1),
|
||||
lessonNumber: z.string().min(1),
|
||||
lessonNote: z.string(),
|
||||
slideUrl: z.string().url().optional(),
|
||||
video: z.array(z.string().url()).optional()
|
||||
})
|
||||
)
|
||||
});
|
||||
export type TCourseDownloadContent = z.infer<typeof ZCourseDownloadContent>;
|
||||
|
||||
export const ZLessonDownloadContent = z.object({
|
||||
title: z.string().min(1),
|
||||
number: z.string().min(1),
|
||||
orgName: z.string().min(1),
|
||||
note: z.string(),
|
||||
slideUrl: z.string().url().optional(),
|
||||
video: z.array(z.string().url()).optional(),
|
||||
courseTitle: z.string().min(1)
|
||||
});
|
||||
export type TLessonDownloadContent = z.infer<typeof ZLessonDownloadContent>;
|
||||
|
||||
export const ZCoursePresignUrlUpload = z.object({
|
||||
fileName: z.string().min(1),
|
||||
fileType: z.enum(ALLOWED_CONTENT_TYPES)
|
||||
});
|
||||
export type TCoursePresignUrlUpload = z.infer<typeof ZCoursePresignUrlUpload>;
|
||||
|
||||
export const ZCourseDocumentPresignUrlUpload = z.object({
|
||||
fileName: z.string().min(1),
|
||||
fileType: z.enum(ALLOWED_DOCUMENT_TYPES)
|
||||
});
|
||||
export type TCourseDocumentPresignUrlUpload = z.infer<typeof ZCourseDocumentPresignUrlUpload>;
|
||||
|
||||
export const ZCourseDownloadPresignedUrl = z.object({
|
||||
keys: z.array(z.string().min(1)).min(1)
|
||||
});
|
||||
export type TCourseDownloadPresignedUrl = z.infer<typeof ZCourseDownloadPresignedUrl>;
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Course Validation Module
|
||||
*
|
||||
* Exports all course-related validation schemas and types.
|
||||
* Use these schemas for validating course operations across API and frontend.
|
||||
*/
|
||||
|
||||
export * from './course';
|
||||
@@ -0,0 +1,7 @@
|
||||
export * from './constants';
|
||||
|
||||
export * from './account';
|
||||
export * from './course';
|
||||
export * from './mail';
|
||||
export * from './onboarding';
|
||||
export * from './organization';
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Mail Validation Module
|
||||
*
|
||||
* Exports all email-related validation schemas and types.
|
||||
* Use these schemas for validating email operations across API and frontend.
|
||||
*/
|
||||
|
||||
export * from './mail';
|
||||
@@ -0,0 +1,13 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const ZEmailData = z.object({
|
||||
from: z.string().optional(),
|
||||
to: z.email(),
|
||||
subject: z.string().min(1),
|
||||
content: z.string().min(1),
|
||||
replyTo: z.string().optional()
|
||||
});
|
||||
export type TEmailData = z.infer<typeof ZEmailData>;
|
||||
|
||||
export const ZDeliverEmail = z.array(ZEmailData).min(1);
|
||||
export type TDeliverEmail = z.infer<typeof ZDeliverEmail>;
|
||||
@@ -0,0 +1 @@
|
||||
export * from './onboarding';
|
||||
@@ -0,0 +1,27 @@
|
||||
import * as z from 'zod';
|
||||
|
||||
const fullnameValidation = z.string().min(5);
|
||||
|
||||
export const ZOnboardingStep1 = z.object({
|
||||
fullname: fullnameValidation,
|
||||
orgName: z
|
||||
.string()
|
||||
.min(5)
|
||||
.refine((val) => !/^[-]|[-]$/.test(val), {
|
||||
message: 'validations.organization_name.hyphen_rule'
|
||||
}),
|
||||
siteName: z
|
||||
.string()
|
||||
.min(5)
|
||||
.refine((val) => !/^[-]|[-]$/.test(val), {
|
||||
message: 'validations.site_name.hyphen_rule'
|
||||
})
|
||||
});
|
||||
export type TOnboardingStep1 = z.infer<typeof ZOnboardingStep1>;
|
||||
|
||||
export const ZOnboardingStep2 = z.object({
|
||||
fullname: fullnameValidation,
|
||||
goal: z.string().min(5),
|
||||
source: z.string().min(5)
|
||||
});
|
||||
export type TOnboardingStep2 = z.infer<typeof ZOnboardingStep2>;
|
||||
@@ -0,0 +1 @@
|
||||
export * from './organization';
|
||||
@@ -0,0 +1,51 @@
|
||||
import * as z from 'zod';
|
||||
|
||||
export const ZGetOrganizations = z.object({
|
||||
siteName: z.string().min(1).optional(),
|
||||
customDomain: z.string().min(1).optional(),
|
||||
isCustomDomainVerified: z.boolean().optional()
|
||||
});
|
||||
|
||||
export type TGetOrganizations = z.infer<typeof ZGetOrganizations>;
|
||||
|
||||
export const ZGetOrganizationTeam = z.object({
|
||||
orgId: z.uuid()
|
||||
});
|
||||
|
||||
export type TGetOrganizationTeam = z.infer<typeof ZGetOrganizationTeam>;
|
||||
|
||||
export const ZGetOrganizationAudience = z.object({
|
||||
orgId: z.uuid()
|
||||
});
|
||||
|
||||
export type TGetOrganizationAudience = z.infer<typeof ZGetOrganizationAudience>;
|
||||
|
||||
export const ZGetCoursesBySiteName = z.object({
|
||||
siteName: z.string().min(1)
|
||||
});
|
||||
|
||||
export type TGetCoursesBySiteName = z.infer<typeof ZGetCoursesBySiteName>;
|
||||
|
||||
export const ZCreateOrgPlan = z.object({
|
||||
orgId: z.uuid(),
|
||||
planName: z.enum(['EARLY_ADOPTER', 'ENTERPRISE', 'BASIC']),
|
||||
subscriptionId: z.string().min(1),
|
||||
triggeredBy: z.number().int().positive(),
|
||||
payload: z.record(z.string(), z.unknown())
|
||||
});
|
||||
|
||||
export type TCreateOrgPlan = z.infer<typeof ZCreateOrgPlan>;
|
||||
|
||||
export const ZUpdateOrgPlan = z.object({
|
||||
subscriptionId: z.string().min(1),
|
||||
payload: z.record(z.string(), z.unknown())
|
||||
});
|
||||
|
||||
export type TUpdateOrgPlan = z.infer<typeof ZUpdateOrgPlan>;
|
||||
|
||||
export const ZCancelOrgPlan = z.object({
|
||||
subscriptionId: z.string().min(1),
|
||||
payload: z.record(z.string(), z.unknown())
|
||||
});
|
||||
|
||||
export type TCancelOrgPlan = z.infer<typeof ZCancelOrgPlan>;
|
||||
Reference in New Issue
Block a user