Compare commits

..
Author SHA1 Message Date
Hafid Nur c463fcedb6 Revert package-lock.json to ensure ci (Nix build & cache) successful 2026-02-14 17:06:39 +07:00
Hafid Nur d08f227e65 Revert package.json to fix ci 2026-02-14 17:01:39 +07:00
Hafid Nur e3b98d9f35 Add deployment script
Add Dockerfile, docker compose, and update Nix config for deployment
2026-02-14 16:44:23 +07:00
Hafid Nur 5bb5a05a25 Develop QR code generator app for campaign 2026-02-14 16:38:15 +07:00
Hafid Nur c79580b4ea Initialize a new NX project - QR campaign 2026-02-13 20:01:51 +07:00
15 changed files with 19 additions and 2318 deletions
@@ -1 +0,0 @@
/nix/store/01x5k4nlxcpyd85nnr0b9gm89rm8ff4x-source
@@ -1 +0,0 @@
/nix/store/8hx8jwa24q6rkzhca9iqy5ckk9rbphi1-source
@@ -1 +0,0 @@
/nix/store/jizz7ld5r2w11y03wrmnvwsskc45krj9-source
@@ -1 +0,0 @@
/nix/store/yj1wxm9hh8610iyzqnz75kvs6xl8j3my-source
@@ -1 +0,0 @@
/nix/store/y4p9szcab9xd7v1c7k9ghr86hb6myyg4-nix-shell-env
File diff suppressed because it is too large Load Diff
+5 -18
View File
@@ -1,23 +1,18 @@
const apps = [
{ name: 'Landing', domain: 'imphnen.dev', type: 'Next.js', color: 'blue' },
{ name: 'WWW', domain: 'www.imphnen.dev', type: 'Redirect', color: 'purple' },
{ name: 'Gacha', domain: 'gacha.imphnen.dev', type: 'Vite', color: 'green' },
{ name: 'Backoffice', domain: 'backoffice.imphnen.dev', type: 'Vite', color: 'green' },
{ name: 'Dimentorin', domain: 'dimentorin.imphnen.dev', type: 'Vite', color: 'green' },
{ name: 'Hackathon', domain: 'hackathon.imphnen.dev', type: 'Vite', color: 'green' },
{ name: 'QR Campaign', domain: 'qr.imphnen.dev', type: 'Vite', color: 'green' },
{ name: 'Infra', domain: 'infra.imphnen.dev', type: 'Vite', color: 'green' },
{ name: 'API QR', domain: 'api-qr.imphnen.dev', type: 'Backend', color: 'orange' },
];
const techStack = [
{ category: 'OS', items: ['NixOS 25.05'] },
{ category: 'OS', items: ['NixOS 24.11'] },
{ category: 'Web Server', items: ['Nginx'] },
{ category: 'SSL', items: ['Let\'s Encrypt (ACME)'] },
{ category: 'Build', items: ['Nix Flakes', 'Nx Monorepo'] },
{ category: 'CI/CD', items: ['GitHub Actions', 'Cachix'] },
{ category: 'Frontend', items: ['React', 'Next.js', 'Vite', 'TailwindCSS'] },
{ category: 'Backend', items: ['Go', 'Supabase'] },
{ category: 'Secrets', items: ['sops-nix'] },
];
@@ -176,23 +171,15 @@ export default function App() {
<div className="w-12 h-12 bg-zinc-800 rounded-full flex items-center justify-center mx-auto mb-2">
<span>2</span>
</div>
<p className="text-sm font-medium">GitHub Actions</p>
<p className="text-xs text-zinc-500">nix build</p>
</div>
<div className="hidden md:block text-zinc-600"></div>
<div className="text-center">
<div className="w-12 h-12 bg-orange-500 rounded-full flex items-center justify-center mx-auto mb-2">
<span>3</span>
</div>
<p className="text-sm font-medium">Push to Cachix</p>
<p className="text-xs text-zinc-500">binary cache</p>
<p className="text-sm font-medium">Update Flake</p>
<p className="text-xs text-zinc-500">nix flake update</p>
</div>
<div className="hidden md:block text-zinc-600"></div>
<div className="text-center">
<div className="w-12 h-12 bg-zinc-800 rounded-full flex items-center justify-center mx-auto mb-2">
<span>4</span>
<span>3</span>
</div>
<p className="text-sm font-medium">Server Pull</p>
<p className="text-sm font-medium">Remote Build</p>
<p className="text-xs text-zinc-500">nixos-rebuild</p>
</div>
<div className="hidden md:block text-zinc-600"></div>
@@ -10,7 +10,6 @@ import {
DeleteOutlined,
CheckCircleOutlined,
PlusOutlined,
FileOutlined,
} from '@ant-design/icons';
export default function CampaignsPage() {
@@ -196,30 +195,7 @@ export default function CampaignsPage() {
</button>
</div>
{!campaigns || campaigns.length === 0 ? (
<div className="bg-white rounded-lg border border-gray-200 p-12 text-center shadow-sm">
<div className="max-w-sm mx-auto">
<div className="text-gray-400 mb-4">
<FileOutlined className="text-[48px] mx-auto" />
</div>
<h3 className="text-lg font-medium text-gray-900 mb-2">
No campaigns yet
</h3>
<p className="text-gray-500 mb-6">
Get started by creating your first QR campaign.
</p>
<button
onClick={() => setShowCreateModal(true)}
className="inline-flex items-center gap-2 bg-primary-500 text-white px-4 py-2 rounded-lg hover:bg-primary-600 transition-colors cursor-pointer"
>
<PlusOutlined />
Create Your First Campaign
</button>
</div>
</div>
) : (
<DataTable data={campaigns} columns={columns} pageSize={10} />
)}
<DataTable data={campaigns} columns={columns} pageSize={10} />
{/* Create Campaign Modal */}
{showCreateModal && (
+2 -18
View File
@@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
import { ColumnDef } from '@tanstack/react-table';
import { DataTable } from '@imphnen-frontend-service/ui/organisms';
import { userService, User } from '../../features/admin/api/user.service';
import { DeleteOutlined, EditOutlined, UserOutlined } from '@ant-design/icons';
import { DeleteOutlined, EditOutlined } from '@ant-design/icons';
export default function UsersPage() {
const [users, setUsers] = useState<User[]>([]);
@@ -193,23 +193,7 @@ export default function UsersPage() {
<p className="text-gray-600 mt-1">Manage users and their roles</p>
</div>
{!users || users.length === 0 ? (
<div className="bg-white rounded-lg border border-gray-200 p-12 text-center shadown-sm">
<div className="max-w-sm mx-auto">
<div className="text-gray-400 mb-4">
<UserOutlined className="text-[48px]" />
</div>
<h3 className="text-lg font-medium text-gray-900 mb-2">
No users found
</h3>
<p className="text-gray-500">
There are currently no users in the system.
</p>
</div>
</div>
) : (
<DataTable data={users} columns={columns} pageSize={10} />
)}
<DataTable data={users} columns={columns} pageSize={10} />
</div>
);
}
@@ -1,7 +1,7 @@
import axios from 'axios';
// Define the base URL for the API
const API_URL = 'https://api-qr.imphnen.dev/api/v1';
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8080/api/v1';
// Create a configured axios instance
export const api = axios.create({
Generated
-61
View File
@@ -1,61 +0,0 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1769170682,
"narHash": "sha256-oMmN1lVQU0F0W2k6OI3bgdzp2YOHWYUAw79qzDSjenU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "c5296fdd05cfa2c187990dd909864da9658df755",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}
+3 -3
View File
@@ -12,7 +12,7 @@
pkgs = import nixpkgs { inherit system; };
# NPM dependencies hash (update with: nix run nixpkgs#prefetch-npm-deps -- package-lock.json)
npmDepsHash = "sha256-6O36QDvjiD7j5MgBhID3+5IeJ47MUeK/025ZTKD0ltU=";
npmDepsHash = "sha256-xmG0ej6GJk1HIFFmrB9CpovNA20sJ7RanFLMBCxKdy0=";
# Import helpers
mkViteApp = import ./nix/mkViteApp.nix {
@@ -45,7 +45,7 @@
# Development shell
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
nodejs
nodejs_22
nodePackages.npm
bun
@@ -116,7 +116,7 @@
mkHackathonWithEnv = envVars: import ./nix/mkViteApp.nix {
pkgs = final;
src = self;
npmDepsHash = "sha256-6O36QDvjiD7j5MgBhID3+5IeJ47MUeK/025ZTKD0ltU=";
npmDepsHash = "sha256-xmG0ej6GJk1HIFFmrB9CpovNA20sJ7RanFLMBCxKdy0=";
} { name = "hackathon"; buildScript = "hackathon:build"; inherit envVars; };
};
};
+2 -2
View File
@@ -10,7 +10,7 @@ pkgs.buildNpmPackage {
makeCacheWritable = true;
nativeBuildInputs = with pkgs; [
nodejs
nodejs_22
nodePackages.npm
python3 # Required for node-gyp (sharp, etc.)
];
@@ -48,7 +48,7 @@ pkgs.buildNpmPackage {
cat > $out/bin/imphnen-landing <<EOF
#!${pkgs.bash}/bin/bash
cd $out/share/landing
exec ${pkgs.nodejs}/bin/node --jitless apps/landing/server.js "\$@"
exec ${pkgs.nodejs_22}/bin/node --jitless apps/landing/server.js "\$@"
EOF
chmod +x $out/bin/imphnen-landing
+1 -1
View File
@@ -12,7 +12,7 @@ pkgs.buildNpmPackage {
makeCacheWritable = true;
nativeBuildInputs = with pkgs; [
nodejs
nodejs_22
nodePackages.npm
util-linux # For script command to create pseudo-terminal
];
+4 -4
View File
@@ -71,7 +71,7 @@
"@tailwindcss/postcss": "^4.0.13",
"@testing-library/dom": "10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "16.1.0",
"@testing-library/react": "^16.1.0",
"@testing-library/user-event": "^14.6.1",
"@types/js-cookie": "^3.0.6",
"@types/node": "^22.12.0",
@@ -9051,9 +9051,9 @@
"license": "MIT"
},
"node_modules/@testing-library/react": {
"version": "16.1.0",
"resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.1.0.tgz",
"integrity": "sha512-Q2ToPvg0KsVL0ohND9A3zLJWcOXXcO8IDu3fj11KhNt0UlCWyFyvnCIBkd12tidB2lkiVRG8VFqdhcqhqnAQtg==",
"version": "16.3.0",
"resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.0.tgz",
"integrity": "sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==",
"dev": true,
"license": "MIT",
"dependencies": {