feat: migrate to Next.js for Mini App and enhance project structure
- Replaced the previous webapp with a new Mini App built using Next.js, improving performance and maintainability. - Updated the `.gitignore` to exclude Next.js build artifacts and node modules. - Revised documentation in `AGENTS.md`, `README.md`, and `architecture.md` to reflect the new Mini App structure and technology stack. - Enhanced Dockerfile to support the new build process for the Next.js application. - Updated CI workflow to build and test the Next.js application. - Added new configuration options for the Mini App, including `MINI_APP_SHORT_NAME` for improved deep linking. - Refactored frontend testing setup to accommodate the new structure and testing framework. - Removed legacy webapp files and dependencies to streamline the project.
This commit is contained in:
76
webapp-next/src/components/AppErrorBoundary.tsx
Normal file
76
webapp-next/src/components/AppErrorBoundary.tsx
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Error boundary that catches render errors in the app tree and shows a fallback
|
||||
* with a reload option. Uses pure i18n (getLang/translate) so it does not depend
|
||||
* on React context that might be broken.
|
||||
*/
|
||||
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { getLang } from "@/i18n/messages";
|
||||
import { translate } from "@/i18n/messages";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
interface AppErrorBoundaryProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
interface AppErrorBoundaryState {
|
||||
hasError: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Catches JavaScript errors in the child tree and renders a fallback UI
|
||||
* instead of crashing. Provides a Reload button to recover.
|
||||
*/
|
||||
export class AppErrorBoundary extends React.Component<
|
||||
AppErrorBoundaryProps,
|
||||
AppErrorBoundaryState
|
||||
> {
|
||||
constructor(props: AppErrorBoundaryProps) {
|
||||
super(props);
|
||||
this.state = { hasError: false };
|
||||
}
|
||||
|
||||
static getDerivedStateFromError(): AppErrorBoundaryState {
|
||||
return { hasError: true };
|
||||
}
|
||||
|
||||
componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
|
||||
if (typeof console !== "undefined" && console.error) {
|
||||
console.error("AppErrorBoundary caught an error:", error, errorInfo);
|
||||
}
|
||||
}
|
||||
|
||||
handleReload = (): void => {
|
||||
if (typeof window !== "undefined") {
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
render(): React.ReactNode {
|
||||
if (this.state.hasError) {
|
||||
const lang = getLang();
|
||||
const message = translate(lang, "error_boundary.message");
|
||||
const reloadLabel = translate(lang, "error_boundary.reload");
|
||||
return (
|
||||
<div
|
||||
className="flex min-h-[200px] flex-col items-center justify-center gap-4 rounded-xl bg-surface py-8 px-4 text-center"
|
||||
role="alert"
|
||||
>
|
||||
<p className="m-0 text-sm font-medium text-foreground">{message}</p>
|
||||
<Button
|
||||
type="button"
|
||||
variant="default"
|
||||
size="sm"
|
||||
onClick={this.handleReload}
|
||||
className="bg-primary text-primary-foreground hover:opacity-90"
|
||||
>
|
||||
{reloadLabel}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user