mirror of
https://github.com/nestriness/nestri.git
synced 2025-12-12 08:45:38 +02:00
⭐ feat(api): Add payments with Polar.sh (#264)
## Description <!-- Briefly describe the purpose and scope of your changes --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced a new subscription API endpoint for managing subscriptions and products. - Enhanced subscription management with new entities and functionalities. - Added functionality to retrieve current timestamps in both local and UTC formats. - Added Polar.sh integration with customer portal and checkout session creation APIs. - **Refactor** - Redesigned team details to now present members and subscription information instead of a plan type. - Enhanced member management by incorporating role assignments. - Streamlined user data handling and removed legacy subscription event logic. - Simplified error handling in actor functions for better clarity. - Updated plan types and UI labels to reflect new subscription tiers. - Improved database indexing for Steam user data. - **Chores** - Updated the database schema with new tables and fields to support subscription, team, and member enhancements. - Extended identifier prefixes to broaden system integration. - Added new secrets related to pricing plans in infrastructure configuration. - Configured API and auth routing with new domain and routing rules. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
@@ -8,8 +8,8 @@ import { useNavigate } from "@solidjs/router";
|
||||
import { useOpenAuth } from "@openauthjs/solid";
|
||||
import { utility } from "@nestri/www/ui/utility";
|
||||
import { useAccount } from "../providers/account";
|
||||
import { Container, Screen as FullScreen } from "@nestri/www/ui/layout";
|
||||
import { FormField, Input, Select } from "@nestri/www/ui/form";
|
||||
import { Container, Screen as FullScreen } from "@nestri/www/ui/layout";
|
||||
import { createForm, getValue, setError, valiForm } from "@modular-forms/solid";
|
||||
|
||||
const nameRegex = /^[a-z0-9\-]+$/
|
||||
@@ -32,8 +32,9 @@ const Hr = styled("hr", {
|
||||
})
|
||||
|
||||
const Plan = {
|
||||
Pro: 'BYOG',
|
||||
Basic: 'Hosted',
|
||||
Free: 'free',
|
||||
Pro: 'pro',
|
||||
Family: 'family',
|
||||
} as const;
|
||||
|
||||
const schema = v.object({
|
||||
@@ -110,6 +111,13 @@ const UrlTitle = styled("span", {
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Renders a form for creating a new team with validated fields for team name, slug, and plan type.
|
||||
*
|
||||
* Submits the form data to the API to create the team, displays validation errors, and navigates to the new team's page upon success.
|
||||
*
|
||||
* @remark If the chosen team slug is already taken, an error message is shown for the slug field.
|
||||
*/
|
||||
export function CreateTeamComponent() {
|
||||
const [form, { Form, Field }] = createForm({
|
||||
validate: valiForm(schema),
|
||||
@@ -215,12 +223,14 @@ export function CreateTeamComponent() {
|
||||
required
|
||||
value={field.value}
|
||||
badges={[
|
||||
{ label: "BYOG", color: "purple" },
|
||||
{ label: "Hosted", color: "blue" },
|
||||
{ label: "Free", color: "gray" },
|
||||
{ label: "Pro", color: "blue" },
|
||||
{ label: "Family", color: "purple" },
|
||||
]}
|
||||
options={[
|
||||
{ label: "I'll be playing on my machine", value: 'BYOG' },
|
||||
{ label: "I'll be playing on the cloud", value: 'Hosted' },
|
||||
{ label: "I'll be playing by myself", value: 'free' },
|
||||
{ label: "I'll be playing with 3 friends", value: 'pro' },
|
||||
{ label: "I'll be playing with 5 family members", value: 'family' },
|
||||
]}
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
@@ -201,15 +201,12 @@ const Nav = styled("nav", {
|
||||
})
|
||||
|
||||
/**
|
||||
* Renders the application's header, featuring navigation, branding, and team details.
|
||||
* Displays the application's fixed top navigation bar with branding, team information, and navigation links.
|
||||
*
|
||||
* This component displays a navigation bar that includes the logo, team avatar, team name, a badge
|
||||
* reflecting the team's plan type, and navigation links. It adjusts its styling based on the scroll
|
||||
* position by toggling visual effects on the navigation wrapper. A scroll event listener is added
|
||||
* on mount to update the header's appearance when the user scrolls and is removed on unmount.
|
||||
* The header includes the app logo, team avatar and name, a badge indicating the team's plan type, and navigation links related to the team. The header's appearance updates dynamically based on the user's scroll position.
|
||||
*
|
||||
* @param props.children - Optional child elements rendered below the header component.
|
||||
* @returns The header component element.
|
||||
* @param props.children - Optional elements rendered below the header.
|
||||
* @returns The rendered header component.
|
||||
*/
|
||||
export function Header(props: ParentProps) {
|
||||
// const team = useContext(TeamContext)
|
||||
@@ -218,7 +215,7 @@ export function Header(props: ParentProps) {
|
||||
id: "tea_01JPACSPYWTTJ66F32X3AWWFWE",
|
||||
slug: "wanjohiryan",
|
||||
name: "Wanjohi",
|
||||
planType: "BYOG"
|
||||
planType: "Pro"
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
@@ -231,8 +228,9 @@ export function Header(props: ParentProps) {
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
|
||||
// const account = useAccount()
|
||||
|
||||
return (
|
||||
<PageWrapper>
|
||||
<NavWrapper scrolled={hasScrolled()}>
|
||||
@@ -294,14 +292,14 @@ export function Header(props: ParentProps) {
|
||||
/>
|
||||
<TeamLabel style={{ color: theme.color.d1000.gray }}>{team!().name}</TeamLabel>
|
||||
<Switch>
|
||||
<Match when={team!().planType === "BYOG"}>
|
||||
<Match when={team!().planType === "Family"}>
|
||||
<Badge style={{ "background-color": theme.color.purple.d700 }}>
|
||||
<span style={{ "line-height": 0 }} >BYOG</span>
|
||||
<span style={{ "line-height": 0 }} >Family</span>
|
||||
</Badge>
|
||||
</Match>
|
||||
<Match when={team!().planType === "Hosted"}>
|
||||
<Match when={team!().planType === "Pro"}>
|
||||
<Badge style={{ "background-color": theme.color.blue.d700 }}>
|
||||
<span style={{ "line-height": 0 }}>Hosted</span>
|
||||
<span style={{ "line-height": 0 }}>Pro</span>
|
||||
</Badge>
|
||||
</Match>
|
||||
</Switch>
|
||||
|
||||
@@ -44,7 +44,7 @@ export const TeamRoute = (
|
||||
return (
|
||||
<Switch>
|
||||
<Match when={!team()}>
|
||||
TODO: Add a public page for (other) teams
|
||||
{/* TODO: Add a public page for (other) teams */}
|
||||
<NotAllowed header />
|
||||
</Match>
|
||||
<Match when={team()}>
|
||||
|
||||
@@ -157,6 +157,7 @@ export const InputRadio = styled("input", {
|
||||
const Label = styled("p", {
|
||||
base: {
|
||||
fontWeight: 500,
|
||||
textAlign: "left",
|
||||
letterSpacing: -0.1,
|
||||
fontSize: theme.font.size.mono_sm,
|
||||
textTransform: "capitalize",
|
||||
@@ -213,6 +214,7 @@ const Hint = styled("p", {
|
||||
fontSize: theme.font.size.xs,
|
||||
lineHeight: theme.font.lineHeight,
|
||||
color: theme.color.gray.d800,
|
||||
textAlign: "left"
|
||||
},
|
||||
variants: {
|
||||
color: {
|
||||
|
||||
Reference in New Issue
Block a user