GitHubgithub.com/xuanhao18044 published projects12 public repositories on GitHub0 stars on GitHub

Project repository

4 of 4 showing
xuanhao1804 / simicart-mobile-app-builderCase study Shipped
BSS Group · 2025–2026

Simicart Mobile App Builder

A Shopify mobile app builder spanning a React/Node.js CMS and customer-facing React Native applications.

ShopifyLiquidReactReact NativeNode.jsREST API
Visit product
ShopifyWeb + mobile commerce product
xuanhao1804 / therafyx-ai-chatbotCase study Shipped
Freelance · 2025

Therafyx AI Chatbot

A guided support chatbot combining Voiceflow, custom extensions, and customer-data workflows.

JavaScriptVoiceflowREST APIUX
Visit product
JavaScriptAI-guided customer support
xuanhao1804 / akaat-test-managementCase study Shipped
FPT Software · 2024

AkaAT Test Management

Product engineering work on a test-management system across frontend, backend, UX, and reliability.

ReactNode.jsAPI TestingTest CasesUI/UX
Visit product
ReactFrontend, backend & testing
xuanhao1804 / treebii-learning-platformCase study Shipped
EdTech BigTreeLand · 2026

Treebii Learning Platform

A learning platform spanning CMS content workflows and a mobile app for English practice and exam preparation.

ReactReact NativeNode.jsCMSEdTech
Visit product
ReactCMS + mobile learning product
reveal-preview.tsx
import { useEffect, useRef, useState } from "react";import type { PointerEvent } from "react";const BG_IMAGE_1 = imageAssets.mountainBase;const BG_IMAGE_2 = imageAssets.mountainReveal;export function RevealPreview() {  const [spotlight, setSpotlight] = useState({ x: 0, y: 0 });  const target = useRef({ x: 0, y: 0 });  const frame = useRef<number | null>(null);  const handlePointerMove = (event: PointerEvent<HTMLDivElement>) => {    const bounds = event.currentTarget.getBoundingClientRect();    target.current = {      x: event.clientX - bounds.left,      y: event.clientY - bounds.top,    };  };  useEffect(() => {    const animate = () => {      setSpotlight((point) => ({        x: point.x + (target.current.x - point.x) * 0.16,        y: point.y + (target.current.y - point.y) * 0.16,      }));      frame.current = requestAnimationFrame(animate);    };    frame.current = requestAnimationFrame(animate);    return () => frame.current && cancelAnimationFrame(frame.current);  }, []);  return (    <div className="code-ui-split__preview-stage" onPointerMove={handlePointerMove}>      <h2 className="code-ui-split__preview-title">        <span className="code-ui-split__preview-title-serif">Layers hold</span>        <span className="code-ui-split__preview-title-sans">tales of time</span>      </h2>      <img className="code-ui-split__image" src={BG_IMAGE_1} alt="" />      <img className="code-ui-split__image code-ui-split__image--reveal" src={BG_IMAGE_2} alt="" />    </div>  );}

Layers holdtales of time