Skip to content

Repository files navigation

Simple-OS KHQR

A modern Vue 3 application with Supabase authentication integration, featuring email, password, and GitHub authentication flows. This project demonstrates how to effectively integrate Supabase with Vue 3, Pinia, Vue-router 4, TailwindCSS, and includes testing with Vitest and Cypress.

Portfolio Portfolio Portfolio Portfolio Portfolio Portfolio Portfolio Linkedin image

Profile Image I'm a Software Developer who passionate about coding and building tools that help people with their daily tasks. I'm currently exploring AI solutions and working with modern tech stacks. I'm also on a journey to level up my Spaghetti Code skills. Support us by make some donate and I really appricate that.

Got a question? Feel free to contact me anytime.

Features

  • 🔐 Complete authentication system with Supabase
  • 📧 Email & Password authentication
  • 🔑 GitHub OAuth integration
  • 💱 KHQR payment integration
  • 🧩 Vue 3 Composition API
  • 🏪 Pinia for state management
  • 🛣️ Vue Router for navigation
  • 🎨 TailwindCSS for styling
  • 🧪 Testing with Vitest and Cypress

Prerequisites

  • Node.js (v16 or later recommended)
  • npm or yarn
  • Git
  • Supabase account

Installation

  1. Clone the repository

    git clone https://github.com/MyKhode/ihub.git
    cd ihub
  2. Install dependencies

    npm install
  3. Create a .env file in the root directory based on the example below:

    VITE_SUPABASE_URL=your_supabase_url
    VITE_SUPABASE_ANON_KEY=your_supabase_anon_key
    

Development Setup

Supabase Configuration

  1. Head over to Supabase and create a new project

  2. Choose your Project name, password, region, and pricing plan (free tier works fine)

  3. Once the project is created, navigate to Authentication > Settings

  4. Configure Site URL and Additional Redirect URLs:

    Field Value
    Site URL https://your-production-url.com/
    Additional Redirect URLs http://localhost:3000/resetpassword, https://your-production-url.com/resetpassword, http://localhost:3000, http://localhost:3000/callback, https://your-production-url.com/callback
  5. Save your changes

Database Setup

To set up the database tables and triggers in Supabase, run the following SQL scripts:

1. Orders Table Setup

-- Create orders table in Supabase
CREATE TABLE orders (
  id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
  product_id INTEGER NOT NULL,
  quantity INTEGER NOT NULL,
  order_number VARCHAR(20) NOT NULL,
  status VARCHAR(20) CHECK (status IN ('active', 'completed', 'cancelled')) NOT NULL,
  date_ordered DATE NOT NULL,
  expected_delivery DATE,
  color VARCHAR(50),
  size VARCHAR(10),
  price VARCHAR(20) NOT NULL,
  product_name VARCHAR(100) NOT NULL,
  product_image TEXT,
  user_id UUID REFERENCES auth.users(id),
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- Create an index on order_number for faster lookups
CREATE INDEX idx_orders_order_number ON orders(order_number);

-- Create an index on status for filtering
CREATE INDEX idx_orders_status ON orders(status);

-- Create a trigger to update the updated_at timestamp
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
  NEW.updated_at = NOW();
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER update_orders_updated_at
BEFORE UPDATE ON orders
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();

-- Set up row level security (RLS)
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;

-- Create policies
-- Policy for users to see only their own orders
CREATE POLICY "Users can view their own orders" ON orders
  FOR SELECT USING (auth.uid() = user_id);

-- Policy for users to insert their own orders
CREATE POLICY "Users can insert their own orders" ON orders
  FOR INSERT WITH CHECK (auth.uid() = user_id);

-- Policy for users to update their own orders
CREATE POLICY "Users can update their own orders" ON orders
  FOR UPDATE USING (auth.uid() = user_id);

-- Policy for users to delete their own orders (optional)
CREATE POLICY "Users can delete their own orders" ON orders
  FOR DELETE USING (auth.uid() = user_id);

2. User Profiles Table Setup

-- Step 1: Drop existing trigger and function
DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users;
DROP FUNCTION IF EXISTS public.handle_new_user;

-- Step 2: Check if table exists, create if it doesn't
DO $$ 
BEGIN
    IF NOT EXISTS (
        SELECT FROM pg_tables 
        WHERE schemaname = 'public' 
        AND tablename = 'user_profiles'
    ) THEN
        CREATE TABLE public.user_profiles (
            user_id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
            email TEXT NOT NULL,
            username TEXT,
            avatar_url TEXT,
            token INTEGER DEFAULT 500,
            created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
            updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
        );
        
        -- Create index for faster lookups
        CREATE INDEX idx_user_profiles_user_id ON public.user_profiles(user_id);
    END IF;
END $$;

-- Step 3: Create the function
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO public.user_profiles (
        user_id,
        email,
        username,
        avatar_url,
        token,
        created_at
    )
    VALUES (
        NEW.id,
        NEW.email,
        COALESCE(NEW.raw_user_meta_data->>'name', ''),
        COALESCE(NEW.raw_user_meta_data->>'avatar_url', ''),
        500,
        NOW()
    )
    ON CONFLICT (user_id) DO UPDATE SET
        email = EXCLUDED.email,
        username = EXCLUDED.username,
        avatar_url = EXCLUDED.avatar_url;
        -- Do NOT update token or created_at for existing users
    RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- Step 4: Create the trigger
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW
EXECUTE FUNCTION public.handle_new_user();

GitHub OAuth Setup (Optional)

  1. Go to GitHub Developer Settings
  2. Create a new OAuth App
  3. Set the Authorization callback URL to your Supabase Auth callback URL (found in Supabase Dashboard)
  4. Copy the Client ID and Client Secret
  5. In Supabase Dashboard, go to Authentication > Providers
  6. Enable GitHub provider and enter your Client ID and Client Secret
  7. Save your changes

KHQR Payment Integration

The KHQR (Khmer QR Code) is a standardized QR code payment system used in Cambodia that enables interoperability between different financial institutions. It allows users to make payments through any bank or payment provider in Cambodia, including popular ones like ABA, Acleda, Wing, and more.

Key Benefits of KHQR

  • Universal Acceptance: Works with all major Cambodian banks and payment providers
  • Convenience: Users can pay using their preferred banking app
  • Security: Transactions are secured through the banking infrastructure
  • Instant Payments: Real-time transaction processing

Technical Setup

  1. Import the KHQR module in your component:

    import { khqr } from 'ts-khqr';
  2. Configure KHQR parameters in your application:

    const qrData = khqr.generate({
      merchantName: 'YOUR_MERCHANT_NAME',
      merchantID: 'YOUR_MERCHANT_ID',
      merchantCity: 'YOUR_CITY',
      amount: transactionAmount,
      currency: 'USD', // or 'KHR' for Cambodian Riel
      acquiringBank: 'YOUR_ACQUIRING_BANK',
      billNumber: 'UNIQUE_BILL_ID'
    });
  3. Generate a QR code using the qrcode library:

    import QRCode from 'qrcode';
    
    // Generate QR code in component
    QRCode.toCanvas(document.getElementById('qr-canvas'), qrData, {
      width: 250,
      margin: 2
    });
  4. Set up payment listener in your Pinia store or component to handle transaction callbacks.

Application Flow

User Journey

  1. Home Page Home Page

    • Users browse available products
    • Select Product to see quick view model pop up
  2. Product Quick View Quick View Product

    • View product details
    • Select size, color, and quantity
    • Click "Buy Now" button and it take a few operation to verify user have enough money and other condition verify
    • Payment Successfully if pass all condition
  3. Top Up Money Top Up Money

    • Users can add funds to their account
    • KHQR payment option enables payment via any Cambodian bank app
    • Scan QR code with banking app (ABA, Acleda, Wing, etc.)
    • Funds are instantly credited to the user's account
  4. Checkout Process

    • Click Product Card to view Product Detail Options
    • Confirm order details
    • Pay using account balance (topped up via KHQR)
  5. Order Confirmation

    • Order is created in the database
    • User receives confirmation by view order history tab
    • Telegram Integration: A notification is sent to the admin Telegram group Telegram Report
  6. Order History Order History

    • Users can view their past orders
    • Track order status (active, completed, cancelled)
    • View expected delivery dates

Running the Application

Development Mode

npm run dev

This will start the development server at http://localhost:3000

Build for Production

npm run build

Preview Production Build

npm run preview

This will serve the production build at http://localhost:5050

Testing

Unit Tests with Vitest

npm run test:vitest

Component Tests with Cypress

npm run test:unit

E2E Tests with Cypress

npm run test:e2e

API Endpoints

If you're using the integrated server functionality:

npm run serve

This will start the server defined in server.js

Deployment

  1. Build your application for production

    npm run build
  2. Deploy the contents of the dist folder to your web hosting service

  3. Make sure to configure your hosting service to handle SPA routing by redirecting all requests to index.html

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT

Links

About

(Free) simple online shopping using khqr payment which accepte any bank in Cambodia

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages