Skip to content

Commit

Permalink
Merge pull request #70 from MinaFoundation/feature/state-improvements
Browse files Browse the repository at this point in the history
Feature/state improvements
  • Loading branch information
iluxonchik authored Dec 6, 2024
2 parents dee2e3a + b6582f8 commit 55951f7
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 32 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "pgt-web-app",
"version": "0.1.9",
"version": "0.1.10",
"private": true,
"type": "module",
"scripts": {
Expand Down
13 changes: 6 additions & 7 deletions src/app/api/me/info/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,24 @@ export async function GET() {
// Get user ID
const userId = deriveUserId(payload.authSource);

// Create user if not exists
await userService.findOrCreateUser(payload.authSource);

// Get complete user info
const userInfo = await userService.getUserInfo(userId);

if (!userInfo) {
return NextResponse.json({ error: "User not found" }, { status: 404 });
return ApiResponse.notFound("User not found");
}

return ApiResponse.success(userInfo);

} catch (error) {
logger.error("User info error:", error);

if (error instanceof Error && error.message === "Invalid token") {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
return ApiResponse.unauthorized("Unauthorized");
}

return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
);
return ApiResponse.error("Internal server error");
}
}
7 changes: 6 additions & 1 deletion src/components/auth/UserStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,12 @@ export function UserStatus() {

// Get auth info from user metadata
const authSource = user.metadata.authSource
const username = user.metadata.username
let username = user.metadata.username

if (authSource.type === 'wallet') {
username = username.slice(0, 6) + '...' + username.slice(-4)
}

const ProviderIcon = AUTH_PROVIDER_ICONS[authSource.type]
const providerName = AUTH_PROVIDER_NAMES[authSource.type]

Expand Down
9 changes: 6 additions & 3 deletions src/components/web3/WalletAuthDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import { useWallet } from "@/contexts/WalletContext";
import { useToast } from "@/hooks/use-toast";
import { WALLET_MESSAGE_VERSIONS, LATEST_WALLET_MESSAGE_VERSION } from "@/constants/wallet-messages";
import { Icons } from "@/components/icons";
import { TransactionPayload } from "@/types/wallet";
import { ApiResponse } from "@/lib/api-response";
import { AppError } from "@/lib/errors";
import { HTTPStatus } from "@/constants/errors";
import { useAuth } from "@/contexts/AuthContext";

interface WalletAuthDialogProps {
open: boolean;
Expand All @@ -29,6 +29,7 @@ interface LinkingDialogProps {
function LinkingDialog({ open, onOpenChange, walletToken, existingToken, onConfirm, onCancel }: LinkingDialogProps) {
const [isLinking, setIsLinking] = useState(false);
const { toast } = useToast();
const { refresh } = useAuth();

const handleConfirm = async () => {
setIsLinking(true);
Expand Down Expand Up @@ -58,6 +59,7 @@ function LinkingDialog({ open, onOpenChange, walletToken, existingToken, onConfi
} finally {
setIsLinking(false);
onOpenChange(false);
await refresh();
}
};

Expand Down Expand Up @@ -94,6 +96,7 @@ function LinkingDialog({ open, onOpenChange, walletToken, existingToken, onConfi
export function WalletAuthDialog({ open, onOpenChange }: WalletAuthDialogProps) {
const { state } = useWallet();
const { toast } = useToast();
const { refresh } = useAuth();
const [isAuthenticating, setIsAuthenticating] = useState(false);
const [showLinkingDialog, setShowLinkingDialog] = useState(false);
const [authTokens, setAuthTokens] = useState<{
Expand Down Expand Up @@ -157,7 +160,6 @@ export function WalletAuthDialog({ open, onOpenChange }: WalletAuthDialogProps)
});
onOpenChange(false);
}

} catch (error) {
toast({
title: "Authentication failed",
Expand All @@ -166,6 +168,7 @@ export function WalletAuthDialog({ open, onOpenChange }: WalletAuthDialogProps)
});
} finally {
setIsAuthenticating(false);
await refresh();
}
};

Expand Down Expand Up @@ -211,7 +214,7 @@ export function WalletAuthDialog({ open, onOpenChange }: WalletAuthDialogProps)
onOpenChange={setShowLinkingDialog}
walletToken={authTokens.walletToken}
existingToken={authTokens.existingToken}
onConfirm={() => {
onConfirm={async () => {
toast({
title: "Accounts linked",
description: "Your accounts have been successfully linked",
Expand Down
14 changes: 6 additions & 8 deletions src/components/web3/dialogs/OCVTransactionDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,13 @@ export function OCVTransactionDialog({
console.log("Connected to network:", network)
}

// Create transaction with memo
const tx = {
// Send payment to self with memo
const response = await mina.sendPayment({
to: account,
amount: "0",
memo,
}

// Send the transaction
const response = await mina.sendTransaction(tx)
amount: 0,
memo: memo,
})

hash = response.hash

break
Expand Down
22 changes: 10 additions & 12 deletions src/contexts/AuthContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,13 @@ interface AuthContextType {
const AuthContext = createContext<AuthContextType | undefined>(undefined)

/**
* Checks if authentication cookies exist
* Checks if user is authenticated.
*
* This will be implemented later, it's not necessry to implement it now.
* The goal of this is to minimize unecessary api calls.
*/
function hasAuthCookies(): boolean {
// Check for either access_token or refresh_token
return document.cookie.split(';').some(cookie => {
const trimmed = cookie.trim()
return trimmed.startsWith('access_token=') || trimmed.startsWith('refresh_token=')
})
function isAuthenticated(): boolean {
return true;
}

export function AuthProvider({ children }: { children: React.ReactNode }) {
Expand All @@ -47,15 +46,14 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {

const refresh = useCallback(async () => {
try {
// Only attempt to fetch user info if we have auth cookies
if (!hasAuthCookies()) {
if (!isAuthenticated()) {
setUser(null)
return
}

const res = await fetch('/api/me/info')

if (res.status === 401) {
if (res.status === 401 || res.status === 403) {
setUser(null)
return
}
Expand All @@ -79,7 +77,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {

useEffect(() => {
// Only run initial auth check if we have cookies
if (hasAuthCookies()) {
if (isAuthenticated()) {
refresh().finally(() => setIsLoading(false))
} else {
setIsLoading(false)
Expand All @@ -93,7 +91,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
const logout = useCallback(async () => {
try {
// Only attempt logout if we have auth cookies
if (!hasAuthCookies()) {
if (!isAuthenticated()) {
setUser(null)
router.push('/')
return
Expand Down
14 changes: 14 additions & 0 deletions src/lib/api-response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ import { HTTPStatus } from '@/constants/errors';
import logger from '@/logging';

export class ApiResponse {
static notFound<T>(data: T | { error: string } | string) {
if (typeof data === 'string') {
data = { error: data };
}
return NextResponse.json(data, { status: HTTPStatus.NOT_FOUND });
}

static unauthorized<T>(data: T | { error: string } | string) {
if (typeof data === 'string') {
data = { error: data };
}
return NextResponse.json(data, { status: HTTPStatus.UNAUTHORIZED });
}

static success<T>(data: T) {
return NextResponse.json(data);
}
Expand Down
1 change: 1 addition & 0 deletions src/services/UserService.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { PrismaClient, User } from "@prisma/client";
import { deriveUserId, generateLinkId } from "@/lib/user/derive";
import type { AuthSource } from "@/lib/user/types";
import logger from "@/logging";

type AuthSourceType = AuthSource['type'];

Expand Down
12 changes: 12 additions & 0 deletions src/types/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,17 @@ interface SignedData {
};
}

interface SendPaymentArgs {
readonly to: string
readonly amount: number
readonly fee?: number
readonly memo?: string
}

type SendTransactionResult = {
hash: string
}

export interface AuroWallet {
requestAccounts(): Promise<string[]>;
getAccounts?(): Promise<string[]>;
Expand All @@ -88,6 +99,7 @@ export interface AuroWallet {
handler: (payload: WalletEventPayload[T]) => void
): void;
signMessage: (args: { message: string }) => Promise<SignedData>;
sendPayment: (args: SendPaymentArgs) => Promise<SendTransactionResult>;
}

declare global {
Expand Down

0 comments on commit 55951f7

Please sign in to comment.