mirror of
https://github.com/lukevella/rallly.git
synced 2025-08-06 09:59:00 +02:00
Update
This commit is contained in:
parent
f838c5401a
commit
22c616e4a0
6 changed files with 78 additions and 100 deletions
|
@ -1,7 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { usePostHog } from "@rallly/posthog/client";
|
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
|
@ -42,7 +41,6 @@ export function OTPForm({ token }: { token: string }) {
|
||||||
const locale = i18n.language;
|
const locale = i18n.language;
|
||||||
|
|
||||||
const queryClient = trpc.useUtils();
|
const queryClient = trpc.useUtils();
|
||||||
const posthog = usePostHog();
|
|
||||||
const authenticateRegistration =
|
const authenticateRegistration =
|
||||||
trpc.auth.authenticateRegistration.useMutation();
|
trpc.auth.authenticateRegistration.useMutation();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
@ -64,11 +62,6 @@ export function OTPForm({ token }: { token: string }) {
|
||||||
|
|
||||||
queryClient.invalidate();
|
queryClient.invalidate();
|
||||||
|
|
||||||
posthog?.identify(res.user.id, {
|
|
||||||
email: res.user.email,
|
|
||||||
name: res.user.name,
|
|
||||||
});
|
|
||||||
|
|
||||||
signIn("registration-token", {
|
signIn("registration-token", {
|
||||||
token,
|
token,
|
||||||
redirectTo: searchParams?.get("redirectTo") ?? "/",
|
redirectTo: searchParams?.get("redirectTo") ?? "/",
|
||||||
|
|
|
@ -27,8 +27,8 @@ const formSchema = z.object({
|
||||||
type FormData = z.infer<typeof formSchema>;
|
type FormData = z.infer<typeof formSchema>;
|
||||||
|
|
||||||
const DateTimePreferencesForm = () => {
|
const DateTimePreferencesForm = () => {
|
||||||
const { timeFormat, weekStart, timeZone, locale } = useDayjs();
|
const { timeFormat, weekStart, timeZone } = useDayjs();
|
||||||
const { preferences, updatePreferences } = usePreferences();
|
const { updatePreferences } = usePreferences();
|
||||||
|
|
||||||
const form = useForm<FormData>({
|
const form = useForm<FormData>({
|
||||||
resolver: zodResolver(formSchema),
|
resolver: zodResolver(formSchema),
|
||||||
|
@ -126,25 +126,6 @@ const DateTimePreferencesForm = () => {
|
||||||
>
|
>
|
||||||
<Trans i18nKey="save" />
|
<Trans i18nKey="save" />
|
||||||
</Button>
|
</Button>
|
||||||
{preferences.timeFormat || preferences.weekStart ? (
|
|
||||||
<Button
|
|
||||||
onClick={async () => {
|
|
||||||
updatePreferences({
|
|
||||||
weekStart: null,
|
|
||||||
timeFormat: null,
|
|
||||||
});
|
|
||||||
form.reset({
|
|
||||||
weekStart: locale.weekStart,
|
|
||||||
timeFormat: locale.timeFormat,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Trans
|
|
||||||
defaults="Use locale defaults"
|
|
||||||
i18nKey="useLocaleDefaults"
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
|
@ -12,6 +12,7 @@ import React from "react";
|
||||||
|
|
||||||
import { TimeZoneChangeDetector } from "@/app/[locale]/timezone-change-detector";
|
import { TimeZoneChangeDetector } from "@/app/[locale]/timezone-change-detector";
|
||||||
import { UserProvider } from "@/components/user-provider";
|
import { UserProvider } from "@/components/user-provider";
|
||||||
|
import { PreferencesProvider } from "@/contexts/preferences";
|
||||||
import { getUser } from "@/data/get-user";
|
import { getUser } from "@/data/get-user";
|
||||||
import { TimezoneProvider } from "@/features/timezone/client/context";
|
import { TimezoneProvider } from "@/features/timezone/client/context";
|
||||||
import { I18nProvider } from "@/i18n/client";
|
import { I18nProvider } from "@/i18n/client";
|
||||||
|
@ -64,27 +65,42 @@ export default async function Root({
|
||||||
<PostHogPageView />
|
<PostHogPageView />
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<UserProvider
|
<UserProvider
|
||||||
user={{
|
user={
|
||||||
id: user?.id ?? session?.user?.id ?? "",
|
user
|
||||||
name: user?.name ?? session?.user?.name ?? "",
|
? {
|
||||||
email: user?.email ?? session?.user?.email ?? undefined,
|
id: user.id,
|
||||||
tier: user ? (user.isPro ? "pro" : "hobby") : "guest",
|
name: user.name,
|
||||||
timeZone:
|
email: user.email,
|
||||||
user?.timeZone ?? session?.user?.timeZone ?? undefined,
|
tier: user
|
||||||
timeFormat: session?.user?.timeFormat ?? undefined,
|
? user.isPro
|
||||||
weekStart: session?.user?.weekStart ?? undefined,
|
? "pro"
|
||||||
image: session?.user?.image ?? undefined,
|
: "hobby"
|
||||||
locale: session?.user?.locale ?? undefined,
|
: "guest",
|
||||||
}}
|
image: user.image,
|
||||||
|
}
|
||||||
|
: session?.user
|
||||||
|
? {
|
||||||
|
id: session.user.id,
|
||||||
|
tier: "guest",
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<TimezoneProvider
|
<PreferencesProvider
|
||||||
initialTimezone={session?.user?.timeZone ?? undefined}
|
initialValue={{
|
||||||
|
timeFormat: user?.timeFormat,
|
||||||
|
timeZone: user?.timeZone,
|
||||||
|
locale: user?.locale,
|
||||||
|
weekStart: user?.weekStart,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<ConnectedDayjsProvider>
|
<TimezoneProvider initialTimezone={user?.timeZone}>
|
||||||
{children}
|
<ConnectedDayjsProvider>
|
||||||
<TimeZoneChangeDetector />
|
{children}
|
||||||
</ConnectedDayjsProvider>
|
<TimeZoneChangeDetector />
|
||||||
</TimezoneProvider>
|
</ConnectedDayjsProvider>
|
||||||
|
</TimezoneProvider>
|
||||||
|
</PreferencesProvider>
|
||||||
</UserProvider>
|
</UserProvider>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
</PostHogProvider>
|
</PostHogProvider>
|
||||||
|
|
|
@ -5,9 +5,7 @@ import { signOut } from "next-auth/react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { useSubscription } from "@/contexts/plan";
|
import { useSubscription } from "@/contexts/plan";
|
||||||
import { PreferencesProvider } from "@/contexts/preferences";
|
|
||||||
import { useTranslation } from "@/i18n/client";
|
import { useTranslation } from "@/i18n/client";
|
||||||
import { trpc } from "@/trpc/client";
|
|
||||||
import { isOwner } from "@/utils/permissions";
|
import { isOwner } from "@/utils/permissions";
|
||||||
|
|
||||||
import { useRequiredContext } from "./use-required-context";
|
import { useRequiredContext } from "./use-required-context";
|
||||||
|
@ -15,14 +13,10 @@ import { useRequiredContext } from "./use-required-context";
|
||||||
type UserData = {
|
type UserData = {
|
||||||
id?: string;
|
id?: string;
|
||||||
name: string;
|
name: string;
|
||||||
email?: string | null;
|
email?: string;
|
||||||
isGuest: boolean;
|
isGuest: boolean;
|
||||||
tier: "guest" | "hobby" | "pro";
|
tier: "guest" | "hobby" | "pro";
|
||||||
timeZone?: string | null;
|
image?: string;
|
||||||
timeFormat?: "hours12" | "hours24" | null;
|
|
||||||
weekStart?: number | null;
|
|
||||||
image?: string | null;
|
|
||||||
locale?: string | null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const UserContext = React.createContext<{
|
export const UserContext = React.createContext<{
|
||||||
|
@ -58,30 +52,37 @@ export const IfGuest = (props: { children?: React.ReactNode }) => {
|
||||||
return <>{props.children}</>;
|
return <>{props.children}</>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type BaseUser = {
|
||||||
|
id: string;
|
||||||
|
tier: "guest" | "hobby" | "pro";
|
||||||
|
image?: string;
|
||||||
|
name?: string;
|
||||||
|
email?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RegisteredUser = BaseUser & {
|
||||||
|
email: string;
|
||||||
|
name: string;
|
||||||
|
tier: "hobby" | "pro";
|
||||||
|
};
|
||||||
|
|
||||||
|
type GuestUser = BaseUser & {
|
||||||
|
tier: "guest";
|
||||||
|
};
|
||||||
|
|
||||||
export const UserProvider = ({
|
export const UserProvider = ({
|
||||||
children,
|
children,
|
||||||
user,
|
user,
|
||||||
}: {
|
}: {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
user?: {
|
user?: RegisteredUser | GuestUser;
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
email?: string;
|
|
||||||
tier: "guest" | "hobby" | "pro";
|
|
||||||
timeZone?: string;
|
|
||||||
timeFormat?: "hours12" | "hours24";
|
|
||||||
weekStart?: number;
|
|
||||||
image?: string;
|
|
||||||
locale?: string;
|
|
||||||
};
|
|
||||||
}) => {
|
}) => {
|
||||||
const subscription = useSubscription();
|
const subscription = useSubscription();
|
||||||
const updatePreferences = trpc.user.updatePreferences.useMutation();
|
const { t } = useTranslation();
|
||||||
const { t, i18n } = useTranslation();
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const posthog = usePostHog();
|
const posthog = usePostHog();
|
||||||
|
|
||||||
const isGuest = !user?.email;
|
const isGuest = !user || user.tier === "guest";
|
||||||
const tier = isGuest ? "guest" : subscription?.active ? "pro" : "hobby";
|
const tier = isGuest ? "guest" : subscription?.active ? "pro" : "hobby";
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
@ -90,9 +91,7 @@ export const UserProvider = ({
|
||||||
email: user.email,
|
email: user.email,
|
||||||
name: user.name,
|
name: user.name,
|
||||||
tier,
|
tier,
|
||||||
timeZone: user.timeZone ?? null,
|
image: user.image,
|
||||||
image: user.image ?? null,
|
|
||||||
locale: user.locale ?? i18n.language,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
@ -104,12 +103,10 @@ export const UserProvider = ({
|
||||||
user: {
|
user: {
|
||||||
id: user?.id,
|
id: user?.id,
|
||||||
name: user?.name ?? t("guest"),
|
name: user?.name ?? t("guest"),
|
||||||
email: user?.email || null,
|
email: user?.email,
|
||||||
isGuest,
|
isGuest,
|
||||||
tier,
|
tier,
|
||||||
timeZone: user?.timeZone ?? null,
|
image: user?.image,
|
||||||
image: user?.image ?? null,
|
|
||||||
locale: user?.locale ?? i18n.language,
|
|
||||||
},
|
},
|
||||||
isAuthenticated: !!user,
|
isAuthenticated: !!user,
|
||||||
refresh: router.refresh,
|
refresh: router.refresh,
|
||||||
|
@ -123,27 +120,7 @@ export const UserProvider = ({
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PreferencesProvider
|
{children}
|
||||||
initialValue={{
|
|
||||||
locale: user?.locale ?? undefined,
|
|
||||||
timeZone: user?.timeZone ?? undefined,
|
|
||||||
timeFormat: user?.timeFormat ?? undefined,
|
|
||||||
weekStart: user?.weekStart ?? undefined,
|
|
||||||
}}
|
|
||||||
onUpdate={async (newPreferences) => {
|
|
||||||
if (!isGuest) {
|
|
||||||
await updatePreferences.mutateAsync({
|
|
||||||
locale: newPreferences.locale ?? undefined,
|
|
||||||
timeZone: newPreferences.timeZone ?? undefined,
|
|
||||||
timeFormat: newPreferences.timeFormat ?? undefined,
|
|
||||||
weekStart: newPreferences.weekStart ?? undefined,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
router.refresh();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</PreferencesProvider>
|
|
||||||
</UserContext.Provider>
|
</UserContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import type { TimeFormat } from "@rallly/database";
|
import type { TimeFormat } from "@rallly/database";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useSetState } from "react-use";
|
import { useSetState } from "react-use";
|
||||||
|
|
||||||
import { useRequiredContext } from "@/components/use-required-context";
|
import { useRequiredContext } from "@/components/use-required-context";
|
||||||
|
import { trpc } from "@/trpc/client";
|
||||||
|
|
||||||
type Preferences = {
|
type Preferences = {
|
||||||
timeZone?: string | null;
|
timeZone?: string | null;
|
||||||
|
@ -23,13 +26,12 @@ const PreferencesContext = React.createContext<PreferencesContextValue | null>(
|
||||||
export const PreferencesProvider = ({
|
export const PreferencesProvider = ({
|
||||||
children,
|
children,
|
||||||
initialValue,
|
initialValue,
|
||||||
onUpdate,
|
|
||||||
}: {
|
}: {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
initialValue: Partial<Preferences>;
|
initialValue: Partial<Preferences>;
|
||||||
onUpdate?: (preferences: Partial<Preferences>) => Promise<void>;
|
|
||||||
}) => {
|
}) => {
|
||||||
const [preferences, setPreferences] = useSetState<Preferences>(initialValue);
|
const [preferences, setPreferences] = useSetState<Preferences>(initialValue);
|
||||||
|
const updatePreferences = trpc.user.updatePreferences.useMutation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PreferencesContext.Provider
|
<PreferencesContext.Provider
|
||||||
|
@ -37,7 +39,12 @@ export const PreferencesProvider = ({
|
||||||
preferences,
|
preferences,
|
||||||
updatePreferences: async (newPreferences) => {
|
updatePreferences: async (newPreferences) => {
|
||||||
setPreferences(newPreferences);
|
setPreferences(newPreferences);
|
||||||
await onUpdate?.(newPreferences);
|
await updatePreferences.mutateAsync({
|
||||||
|
locale: newPreferences.locale ?? undefined,
|
||||||
|
timeZone: newPreferences.timeZone ?? undefined,
|
||||||
|
timeFormat: newPreferences.timeFormat ?? undefined,
|
||||||
|
weekStart: newPreferences.weekStart ?? undefined,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -18,6 +18,8 @@ export const getUser = cache(async () => {
|
||||||
image: true,
|
image: true,
|
||||||
locale: true,
|
locale: true,
|
||||||
timeZone: true,
|
timeZone: true,
|
||||||
|
timeFormat: true,
|
||||||
|
weekStart: true,
|
||||||
subscription: {
|
subscription: {
|
||||||
select: {
|
select: {
|
||||||
active: true,
|
active: true,
|
||||||
|
@ -37,6 +39,8 @@ export const getUser = cache(async () => {
|
||||||
image: user.image ?? undefined,
|
image: user.image ?? undefined,
|
||||||
locale: user.locale ?? undefined,
|
locale: user.locale ?? undefined,
|
||||||
timeZone: user.timeZone ?? undefined,
|
timeZone: user.timeZone ?? undefined,
|
||||||
|
timeFormat: user.timeFormat ?? undefined,
|
||||||
|
weekStart: user.weekStart ?? undefined,
|
||||||
isPro: user.subscription?.active ?? false,
|
isPro: user.subscription?.active ?? false,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue