diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml
index c3a490f..e0231da 100644
--- a/.github/workflows/static.yml
+++ b/.github/workflows/static.yml
@@ -60,6 +60,7 @@ jobs:
env:
VITE_VALIDATE_PROMOTION_CODE_API: ${{ secrets.VITE_VALIDATE_PROMOTION_CODE_API || 'https://chubgame.com/wp-json/chubgame/v1/validate' }}
VITE_SEND_DICE_DATA_API: ${{ secrets.VITE_SEND_DICE_DATA_API || 'https://chubgame.com/wp-json/chubgame/v1/send' }}
+ VITE_CHECK_BALANCE_API: ${{ secrets.VITE_CHECK_BALANCE_API || 'https://chubgame.com/wp-json/chubgame/v1/check-balance' }}
VITE_MAX_DICE_AMOUNT: ${{ secrets.VITE_MAX_DICE_AMOUNT || 10 }}
run: npm run build
diff --git a/API_Implementation.md b/API_Implementation.md
new file mode 100644
index 0000000..c867731
--- /dev/null
+++ b/API_Implementation.md
@@ -0,0 +1,634 @@
+## Action Table
+
+| Name | Is Used | Description |
+| --- | --- | --- |
+| **GET** | Yes | Retrieve a users current balance. |
+| **CREDIT** | Yes | Add points to a users current balance. |
+| **DEBIT** | Yes | Deduct points from a users balance. |
+| **PAY** | No | Transfer points from one user to another. |
+
+## Hook Initialization for myCred
+
+```php
+/**
+ * Custom Hook: Dice Game Points
+ * This hook handles participation, win, and loss in a single function.
+ */
+add_action( 'mycred_setup_hooks', 'mycredpro_register_dice_game_hook' );
+function mycredpro_register_dice_game_hook( $installed ) {
+
+ $installed['dice_game'] = array(
+ 'title' => __( '%plural% for Dice Game', 'mycredcu' ),
+ 'description' => __( 'Award %_plural% points based on participation, winning, and losing in the dice game.', 'mycredcu' ),
+ 'callback' => array( 'myCRED_Hook_Dice_Game' )
+ );
+
+ return $installed;
+}
+
+/**
+ * Custom Hook: Load Dice Game Hook
+ */
+add_action( 'mycred_load_hooks', 'mycredpro_load_dice_game_hook', 10 );
+function mycredpro_load_dice_game_hook() {
+
+ class myCRED_Hook_Dice_Game extends myCRED_Hook {
+
+ /**
+ * Construct
+ */
+ function __construct( $hook_prefs, $type = 'mycred_default' ) {
+ parent::__construct( array(
+ 'id' => 'dice_game',
+ 'defaults' => array(
+ 'participation_points' => 10, // Fixed points for participation
+ 'win_points' => 10, // Default win points
+ 'win_points_max' => 5000, // Max win points
+ 'win_points_min' => 5, // Min win points
+ 'loss_points' => 10, // Default loss points
+ 'loss_points_max' => 5000, // Max loss points
+ 'loss_points_min' => 5, // Min loss points
+ 'log' => '%plural% for playing the dice game'
+ )
+ ), $hook_prefs, $type );
+ }
+
+ /**
+ * Run the hook
+ */
+ public function run() {
+ add_action( 'dice_game_event', array( $this, 'handle_dice_game_event' ), 10, 3 );
+ }
+
+ /**
+ * Handle Dice Game Event
+ * Handles all actions: participation, win, loss
+ */
+ public function handle_dice_game_event( $user_id, $result ) {
+ // Ensure that the user is not excluded
+ if ( $this->core->exclude_user( $user_id ) === true ) return;
+
+ // Handle participation (always happens)
+ $this->award_participation_points( $user_id );
+
+ // Handle win or loss based on the game result
+ if ( $result == 'win' ) {
+ $this->award_win_points( $user_id );
+ } elseif ( $result == 'loss' ) {
+ $this->deduct_loss_points( $user_id );
+ }
+ }
+
+ /**
+ * Award Participation Points
+ */
+ private function award_participation_points( $user_id ) {
+ $points = $this->prefs['participation_points'];
+
+ // Add points for participation
+ $this->core->add_creds(
+ 'dice_game_participation',
+ $user_id,
+ $points,
+ $this->prefs['log'],
+ 0,
+ array( 'ref_type' => 'dice_game_participation' ),
+ $this->mycred_type
+ );
+ }
+
+ /**
+ * Award Win Points - Handled by external script
+ */
+ private function award_win_points( $user_id ) {
+ // Get win points from the external script or default to 10
+ $points = apply_filters( 'dice_game_win_points', 10 );
+
+ // Clamp points to max/min limits
+ $points = $this->clamp_points($points, 'win');
+
+ // Add points for winning
+ $this->core->add_creds(
+ 'dice_game_win',
+ $user_id,
+ $points,
+ $this->prefs['log'],
+ 0,
+ array( 'ref_type' => 'dice_game_win' ),
+ $this->mycred_type
+ );
+ }
+
+ /**
+ * Deduct Loss Points - Handled by external script
+ */
+ private function deduct_loss_points( $user_id ) {
+ // Get loss points from the external script or default to 10
+ $points = apply_filters( 'dice_game_loss_points', 10 );
+
+ // Clamp points to max/min limits
+ $points = $this->clamp_points($points, 'loss');
+
+ // Get the user's current balance
+ $current_balance = $this->core->get_users_balance( $user_id );
+
+ // Check if the player has enough points
+ if ( $current_balance < $points ) {
+ return new WP_REST_Response(array('valid' => false, 'error' => 'Not enough points to cover the loss'), 400);
+ }
+
+ // Deduct points for losing
+ $this->core->add_creds(
+ 'dice_game_loss',
+ $user_id,
+ -$points, // Negative for deduction
+ $this->prefs['log'],
+ 0,
+ array( 'ref_type' => 'dice_game_loss' ),
+ $this->mycred_type
+ );
+ }
+
+ /**
+ * Clamp Points to Max/Min Limits
+ *
+ * @param int $points The points to be clamped.
+ * @param string $type The type of points, either 'win' or 'loss'.
+ * @return int The clamped points.
+ */
+ private function clamp_points( $points, $type ) {
+ $min = isset($this->prefs["{$type}_points_min"]) ? $this->prefs["{$type}_points_min"] : 0;
+ $max = isset($this->prefs["{$type}_points_max"]) ? $this->prefs["{$type}_points_max"] : PHP_INT_MAX;
+
+ return max($min, min($points, $max));
+ }
+
+ /**
+ * Preferences Page
+ * Define the settings for the hook.
+ */
+ public function preferences() {
+ $prefs = $this->prefs;
+ ?>
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+ prefix . 'dice_data';
+ $charset_collate = $wpdb->get_charset_collate();
+
+ $sql = "CREATE TABLE $table_name (
+ id mediumint(9) NOT NULL AUTO_INCREMENT,
+ user_id bigint(20) NOT NULL,
+ dice_amount int(11) NOT NULL,
+ total_points int(11) NOT NULL,
+ promotion_code varchar(16) NOT NULL,
+ is_promotion_user tinyint(1) NOT NULL,
+ chips int(11) NOT NULL,
+ deduct_chips int(11) NOT NULL DEFAULT 0,
+ increase_chips int(11) NOT NULL DEFAULT 0,
+ total_chips int(11) NOT NULL,
+ parent_user_id bigint(20) DEFAULT NULL,
+ child_user_id bigint(20) DEFAULT NULL,
+ created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ PRIMARY KEY (id),
+ KEY user_id_idx (user_id),
+ KEY promotion_code_idx (promotion_code),
+ FOREIGN KEY (parent_user_id) REFERENCES {$wpdb->prefix}users(ID) ON DELETE CASCADE,
+ FOREIGN KEY (child_user_id) REFERENCES {$wpdb->prefix}users(ID) ON DELETE CASCADE
+ ) $charset_collate;";
+
+ require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
+ dbDelta($sql);
+}
+
+register_activation_hook(__FILE__, 'create_dice_data_table');
+```
+
+### Promotion Code Validation Script
+
+Modify the `handle_validate_promotion_code` function to relate the parent user with the promotion code:
+
+```php
+add_action('rest_api_init', function () {
+ register_rest_route('chubgame/v1', '/validate', array(
+ 'methods' => 'POST',
+ 'callback' => 'handle_validate_promotion_code',
+ 'permission_callback' => 'check_if_user_logged_in',
+ ));
+});
+
+function handle_validate_promotion_code(WP_REST_Request $request) {
+ global $wpdb;
+
+ $promotion_code = $request->get_param('promotionCode');
+ $username = $request->get_param('username');
+
+ // Debug: Log received parameters
+ error_log("handle_validate_promotion_code: Received promotion code: $promotion_code, username: $username");
+
+ // Check if the parameters are provided
+ if (empty($promotion_code) || empty($username)) {
+ error_log("handle_validate_promotion_code: Missing parameters (promotion code or username).");
+ $error = new WP_Error(400, 'Promotion code and username are required.', array('status' => 'missing_parameters'));
+ return new WP_REST_Response($error, 400);
+ }
+
+ // Get child user ID
+ $child_user = get_user_by('login', $username);
+ if (!$child_user) {
+ error_log("handle_validate_promotion_code: No user found with username $username");
+ $error = new WP_Error(404, 'Invalid username', array('status' => 'no_user'));
+ return new WP_REST_Response($error, 404);
+ }
+ $child_user_id = $child_user->ID;
+ error_log("handle_validate_promotion_code: Child user ID for username $username is $child_user_id");
+
+ // Validate promotion code and fetch parent user where the user is the promotion code generator
+ $table_name = $wpdb->prefix . 'dice_data';
+ $result = $wpdb->get_row($wpdb->prepare(
+ "SELECT * FROM $table_name WHERE promotion_code = %s AND is_promotion_user = 1",
+ $promotion_code
+ ));
+
+ if (!$result) {
+ error_log("handle_validate_promotion_code: Invalid promotion code or no promotion code generator found for code $promotion_code");
+ $error = new WP_Error(400, 'Invalid promotion code', array('status' => 'invalid_promotion_code'));
+ return new WP_REST_Response($error, 400);
+ }
+
+ // Check if the promotion code has already been used
+ $used_result = $wpdb->get_row($wpdb->prepare(
+ "SELECT * FROM $table_name WHERE promotion_code = %s AND parent_user_id IS NOT NULL AND child_user_id IS NOT NULL",
+ $promotion_code
+ ));
+
+ if ($used_result) {
+ error_log("handle_validate_promotion_code: Promotion code $promotion_code has already been used.");
+ $error = new WP_Error(400, 'This promotion code has already been used', array('status' => 'promotion_code_used'));
+ return new WP_REST_Response($error, 400);
+ }
+
+ // If valid, associate the parent and child users
+ $wpdb->update($table_name, array(
+ 'parent_user_id' => $result->user_id
+ ), array('id' => $result->id));
+
+ error_log("handle_validate_promotion_code: Parent user ID {$result->user_id} associated with child user ID $child_user_id");
+
+ return new WP_REST_Response(array(
+ 'code' => 200,
+ 'message' => 'Promotion code is valid and successfully applied.',
+ 'data' => array(
+ 'status' => 'success',
+ 'valid' => true,
+ 'parent_user_id' => $result->user_id
+ )
+ ), 200);
+}
+
+```
+
+### Balance Validation Script
+
+```php
+add_action('rest_api_init', function () {
+ register_rest_route('chubgame/v1', '/check-balance', array(
+ 'methods' => 'POST',
+ 'callback' => 'handle_check_balance',
+ 'permission_callback' => 'check_if_user_logged_in',
+ ));
+});
+
+function handle_check_balance(WP_REST_Request $request) {
+ global $wpdb;
+
+ // Get the request parameters
+ $username = $request->get_param('username');
+ $chips = $request->get_param('chips'); // The chips (bet amount) to be checked
+
+ // Log the request parameters for debugging
+ error_log("Check Balance Request: username={$username}, chips={$chips}");
+
+ // Check if the parameters are provided
+ if (empty($username) || empty($chips)) {
+ error_log("Error: Missing parameters (username or chips).");
+
+ $error = new WP_Error(400, 'Username and chips are required.', array('status' => 'missing_parameters'));
+ return new WP_REST_Response($error, 400);
+ }
+
+ // Get the user by their username
+ $user = get_user_by('login', $username);
+ if (!$user) {
+ error_log("Error: No user found for username {$username}.");
+
+ $error = new WP_Error(404, 'Invalid username', array('status' => 'no_user'));
+ return new WP_REST_Response($error, 400);
+ }
+ $user_id = $user->ID;
+ error_log("User found: {$username}, user_id={$user_id}");
+
+ // Get the current balance for the user
+ $current_balance = mycred_get_users_balance($user_id);
+ error_log("Current balance for user_id {$user_id}: {$current_balance}");
+
+ // Check if the user's balance is greater than or equal to the deducted chips
+ if ($current_balance >= $chips) {
+ // Balance is sufficient, return success
+ error_log("Balance is sufficient for {$username} (user_id={$user_id}). Returning success.");
+ return new WP_REST_Response(array(
+ 'code' => 200,
+ 'message' => 'Balance is sufficient for current user',
+ 'data' => array(
+ 'status' => 'success',
+ 'balance' => $current_balance
+ )
+ ), 200);
+ } else {
+ $error = new WP_Error(400, 'Insufficient balance for parent user', array(
+ 'status' => 'insufficient_balance',
+ 'balance' => $current_balance,
+ 'requested_chips' => $chips
+ ));
+ error_log("Error: Insufficient balance for parent user");
+ return new WP_REST_Response($error, 400);
+ }
+}
+
+```
+
+### Dice Data and Manage Chips Script
+
+Update the `handle_send_dice_data` function to:
+
+1. Deduct chips from the parent and child wallets using **myCRED**.
+2. Determine the winner and distribute chips accordingly.
+3. Deduct a 0.5% service charge.
+4. Each promotion code can be used for ONLY ONCE!
+5.
+
+```php
+add_action('rest_api_init', function () {
+ register_rest_route('chubgame/v1', '/send', array(
+ 'methods' => 'POST',
+ 'callback' => 'handle_send_dice_data',
+ 'permission_callback' => 'check_if_user_logged_in',
+ ));
+});
+
+function check_if_user_logged_in() {
+ return is_user_logged_in();
+}
+
+function handle_send_dice_data(WP_REST_Request $request) {
+ global $wpdb;
+
+ // Extract request parameters
+ $dice_amount = $request->get_param('diceAmount');
+ $total_points = $request->get_param('totalPoints');
+ $promotion_code = $request->get_param('promotionCode');
+ $is_promotion_user = $request->get_param('isPromotionUser');
+ $username = $request->get_param('username');
+ $chips = $request->get_param('chips'); // Chips of the current user
+
+ error_log("Received parameters: diceAmount=$dice_amount, totalPoints=$total_points, promotionCode=$promotion_code, isPromotionUser=$is_promotion_user, username=$username, chips=$chips");
+
+ // Check if the parameters are provided
+ if (empty($dice_amount) || empty($total_points) || empty($promotion_code) || !isset($is_promotion_user) || empty($username) || empty($chips)) {
+ // Parameters are missing, return an error
+ $error = new WP_Error(400, 'All parameters are required.', array('status' => 'missing_parameters'));
+ error_log("Error: Missing parameters");
+ return new WP_REST_Response($error, 400);
+ }
+
+ // Get user ID
+ $user = get_user_by('login', $username);
+ if (!$user) {
+ $error = new WP_Error(400, 'Invalid username', array('status' => 'no_user'));
+ error_log("Error: Invalid username");
+ return new WP_REST_Response($error, 404);
+ }
+ $user_id = $user->ID;
+ error_log("User ID: $user_id");
+
+ // Check if the promotion code has already been used
+ $promotion_entry = $wpdb->get_row($wpdb->prepare(
+ "SELECT * FROM {$wpdb->prefix}dice_data WHERE promotion_code = %s AND (parent_user_id IS NOT NULL OR child_user_id IS NOT NULL)",
+ $promotion_code
+ ));
+
+ if ($promotion_entry) {
+ $error = new WP_Error(400, 'This promotion code has already been used', array('status' => 'promotion_used'));
+ error_log("Error: Promotion code already used");
+ return new WP_REST_Response($error, 400);
+ }
+
+ // Common operations for both parent and child users
+ $child_balance = mycred_get_users_balance($user_id);
+ error_log("Child balance: $child_balance");
+
+ // If the user is a parent, we don't need to query the parent from the promotion code
+ if ($is_promotion_user) {
+ $parent_balance = mycred_get_users_balance($user_id);
+ error_log("Parent balance: $parent_balance");
+
+ if ($parent_balance < $chips) {
+ $error = new WP_Error(400, 'Insufficient balance for parent user', array('status' => 'insufficient_balance'));
+ error_log("Error: Insufficient balance for parent user");
+ return new WP_REST_Response($error, 400);
+ }
+
+ // Deduct chips from parent user
+ mycred_subtract('dice_game_loss', $user_id, $chips, 'Dice game loss');
+ $parent_balance = mycred_get_users_balance($user_id); // Updated balance
+ error_log("Updated parent balance after deduction: $parent_balance");
+
+ // Log dice data for parent
+ $wpdb->insert($wpdb->prefix . 'dice_data', array(
+ 'user_id' => $user_id,
+ 'dice_amount' => $dice_amount,
+ 'total_points' => $total_points,
+ 'promotion_code' => $promotion_code,
+ 'is_promotion_user' => $is_promotion_user,
+ 'chips' => $chips,
+ 'deduct_chips' => $chips,
+ 'increase_chips' => 0,
+ 'total_chips' => $parent_balance,
+ 'parent_user_id' => null,
+ 'child_user_id' => null,
+ 'created_at' => current_time('mysql'),
+ ));
+ error_log("Logged dice data for parent user");
+
+ return new WP_REST_Response(array(
+ 'code' => 200,
+ 'message' => 'Parent game processed successfully',
+ 'data' => array(
+ 'status' => 'success',
+ 'balance' => $parent_balance
+ )
+ ), 200);
+ } else {
+ // If the user is a child, find the parent by promotion code
+ $parent_entry = $wpdb->get_row($wpdb->prepare(
+ "SELECT * FROM {$wpdb->prefix}dice_data WHERE promotion_code = %s AND is_promotion_user = 1",
+ $promotion_code
+ ));
+
+ if (!$parent_entry) {
+ $error = new WP_Error(404, 'Invalid promotion code or parent not found', array('status' => 'no_parent'));
+ error_log("Error: Invalid promotion code or parent not found");
+ return new WP_REST_Response($error, 404);
+ }
+
+ $parent_user_id = $parent_entry->user_id;
+ $parent_balance = mycred_get_users_balance($parent_user_id);
+ error_log("Parent user ID: $parent_user_id, Parent balance: $parent_balance");
+
+ // Ensure child has enough balance and refund parent if not
+ if ($child_balance < $chips) {
+ // Refund parent if child has insufficient balance
+ mycred_add('dice_game_win', $parent_user_id, $parent_balance, 'Refund for insufficient child points');
+ $error = new WP_Error(400, 'Child user does not have enough points. Parent refunded.', array('status' => 'insufficient_balance'));
+ error_log("Error: Child user does not have enough points. Parent refunded.");
+ return new WP_REST_Response($error, 400);
+ }
+
+ // Deduct chips from child user
+ mycred_subtract('dice_game_loss', $user_id, $chips, 'Dice game loss');
+ $child_balance = mycred_get_users_balance($user_id); // Updated child balance
+ error_log("Updated child balance after deduction: $child_balance");
+
+ // Calculate winner and loser
+ $winner_user_id = ($total_points > $parent_entry->total_points) ? $user_id : $parent_user_id;
+ error_log("Winner user ID: $winner_user_id");
+
+ // Service charge and winner chips calculation
+ $total_chips = $chips + $parent_entry->chips;
+ $service_charge = $total_chips * 0.005; // 0.5% service charge
+ $winner_chips = $total_chips - $service_charge;
+ error_log("Total chips: $total_chips, Service charge: $service_charge, Winner chips: $winner_chips");
+
+ // Add chips to the winner
+ mycred_add('dice_game_win', $winner_user_id, $winner_chips, 'Dice game win');
+
+ // Update both the parent and the child balance
+ $parent_balance = mycred_get_users_balance($parent_user_id);
+ $child_balance = mycred_get_users_balance($user_id); // Updated child balance
+ error_log("Updated parent balance: $parent_balance, Updated child balance: $child_balance");
+
+ // Log dice data for the child user
+ $wpdb->insert($wpdb->prefix . 'dice_data', array(
+ 'user_id' => $user_id,
+ 'dice_amount' => $dice_amount,
+ 'total_points' => $total_points,
+ 'promotion_code' => $promotion_code,
+ 'is_promotion_user' => $is_promotion_user,
+ 'chips' => $chips,
+ 'deduct_chips' => $chips,
+ 'increase_chips' => $winner_chips,
+ 'total_chips' => $child_balance,
+ 'parent_user_id' => $parent_user_id,
+ 'child_user_id' => null,
+ 'created_at' => current_time('mysql'),
+ ));
+ error_log("Logged dice data for child user");
+
+ // Log dice data for the parent user
+ $wpdb->insert($wpdb->prefix . 'dice_data', array(
+ 'user_id' => $parent_user_id,
+ 'dice_amount' => $dice_amount,
+ 'total_points' => $total_points,
+ 'promotion_code' => $promotion_code,
+ 'is_promotion_user' => $is_promotion_user,
+ 'chips' => $parent_entry->chips,
+ 'deduct_chips' => 0,
+ 'increase_chips' => $winner_chips,
+ 'total_chips' => $parent_balance,
+ 'parent_user_id' => null,
+ 'child_user_id' => $user_id,
+ 'created_at' => current_time('mysql'),
+ ));
+ error_log("Logged dice data for parent user");
+
+ return new WP_REST_Response(array(
+ 'code' => 200,
+ 'message' => 'Game processed successfully',
+ 'data' => array(
+ 'status' => 'success',
+ 'balance' => $child_balance
+ )
+ ), 200);
+ }
+}
+
+```
\ No newline at end of file
diff --git a/README.md b/README.md
index 78f0ca2..e1d6acf 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,28 @@ Now you can find a live version at [here](https://dice,chubgame.com/).
- Randomized Initial Dice Positioning: Enhances realism by randomizing starting positions, resulting in more authentic outcomes.
- Display Dice Roll Results: Shows the sum of the dice roll results, providing users with instant feedback.
+## How to Play the Game
+
+### Parent User
+
+1. Connect to the wallet first.
+2. After connecting, clicks the "Play Now" button of the Dice Game to start the game, then the game page will be popped up.
+3. Click "Skip" button of the "Promotion Code" dialog to skip the promotion code. (Parent user doesn't need to input the promotion code)
+4. Select the pre-defined chip amount or input the custom chip amount, then press the "Start" button to start the game.
+5. Click "+" or "-" button to increase or decrease the number of dices, then press the "Roll" button to roll the dices, then the dices will be rolled, after the dices stop rolling, the total points will be displayed.
+6. Click "Generate" button of the "Total Points" dialog to generate the promotion code, then the user data will be sent to the wordpress server. We will automatically deduct the chip amount from the parent user's wallet.
+7. If the parent user's total dice points are greater than the child user, we will firstly deduct the 0.5% for the service charge, then the parent user will get both the parent user's and the child user's chip amount. Otherwise, the parent user will lose the chip amount.
+
+### Child User
+
+1. Connect to the wallet first.
+2. After connecting, clicks the "Play Now" button of the Dice Game to start the game, then the game page will be popped up.
+3. Input the promotion code, then press the "Submit" button to submit the promotion code.
+4. Select the pre-defined chip amount or input the custom chip amount, then press the "Start" button to start the game.
+5. Click "+" or "-" button to increase or decrease the number of dices, then press the "Roll" button to roll the dices, then the dices will be rolled, after the dices stop rolling, the total points will be displayed.
+6. Click "Save" button of the "Total Points" dialog to save the user data to the wordpress server. We will automatically deduct the chip amount from the child user's wallet.
+7. If the child user's total dice points are greater than the parent user, we will firstly deduct the 0.5% for the service charge, then the child user will get both the parent user's and the child user's chip amount. Otherwise, the child user will lose the chip amount.
+
## Installation
### Clone the repository
@@ -51,84 +73,188 @@ npm run dev
## WordPress API Endpoints
-### Validate Promotion Code
+### Flowchart for the Validate Promotion Code
-This endpoint validates the promotion code provided by the user.
+Promotion Code Verification for Child User:
-**Endpoint:**
+```mermaid
+sequenceDiagram
+ participant User
+ participant API
+ participant Database
-```text
-POST /wp-json/dice-roller/v1/validate
+ User->>API: Send POST /wp-json/dice-roller/v1/validate with promotionCode and username
+ API->>Database: Query promotion_codes table for promotionCode
+ Database->>API: Return promotion code record (valid or not)
+ API->>User: Return response with valid status or error message
```
-**Request Body:**
+### Flowchart for the Send Dice Data
+
+Parent User Sequence Diagram:
+
+```mermaid
+sequenceDiagram
+ participant Parent as Parent User
+ participant WP as WordPress Database
+ participant Dice as Dice Game Logic
+
+ Parent->>WP: Register with Promotion Code
+ WP->>Dice: Store Promotion Code as Parent
+ Dice->>WP: Save Parent User and Chips Info
+ Parent->>Dice: Trigger Dice Game (Win/Loss)
+ Dice->>WP: Update Parent Points (Win/Loss)
+ Dice->>WP: Check Promotion Code for Validity
+ WP->>Dice: Validate Promotion Code
+ Dice->>Parent: Notify Promotion Code Valid
+ Dice->>Parent: Adjust Points and Chips Based on Game Result
+```
+
+Child User Sequence Diagram:
+
+```mermaid
+sequenceDiagram
+ participant Child as Child User
+ participant WP as WordPress Database
+ participant Dice as Dice Game Logic
+
+ Child->>WP: Submit Username and Promotion Code
+ WP->>Dice: Check for Parent User by Promotion Code
+ Dice->>WP: Retrieve Parent User (from Promo Code)
+ WP->>Child: Return Parent User Info
+ Child->>WP: Deduct Chips (if Not Promotion User)
+ Dice->>WP: Deduct Chips for Parent/Child Users (Win/Loss)
+ Dice->>Child: Notify Participation and Points Update
+ Child->>Dice: Trigger Dice Game (Win/Loss)
+ Dice->>WP: Update Points (Win/Loss for Child)
+ Dice->>Child: Notify Points and Chips After Game
+```
+
+## Promotion Code Validation API
+
+Validates a promotion code and associates the parent user with the promotion code.
+
+### Endpoint
+
+`POST /chubgame/v1/validate`
+
+### Parameters
+
+- `promotionCode` (string): The promotion code to validate.
+- `username` (string): The username of the child user.
+
+### Response
+
+#### Success
```json
{
- "promotionCode": "string",
- "username": "string"
+ "code": 200,
+ "message": "Promotion code is valid and successfully applied.",
+ "data": {
+ "status": "success",
+ "valid": true,
+ "parent_user_id": 123
+ }
}
```
-**Response:**
+#### Error
-- **200 OK**: If the promotion code is valid.
+```json
+{
+ "code": 400,
+ "message": "Invalid promotion code",
+ "data": {
+ "status": "invalid_promotion_code"
+ }
+}
+```
- ```json
- {
- "valid": true
- }
- ```
+## Balance Validation API
-- **400 Bad Request**: If the promotion code is invalid.
+Checks if the user has sufficient balance for the specified chips.
- ```json
- {
- "valid": false,
- "error": "Invalid promotion code"
- }
- ```
+### Endpoint
-### Send Dice Data
+`POST /chubgame/v1/check-balance`
-This endpoint sends the dice data to the backend.
+### Parameters
-**Endpoint:**
+- `username` (string): The username of the user.
+- `chips` (int): The number of chips to check.
-```text
-POST /wp-json/dice-roller/v1/send
+### Response
+
+#### Success
+
+```json
+{
+ "code": 200,
+ "message": "Balance is sufficient for current user",
+ "data": {
+ "status": "success",
+ "balance": 1000
+ }
+}
```
-**Request Body:**
+#### Error
```json
{
- "diceAmount": "integer",
- "totalPoints": "integer",
- "promotionCode": "string",
- "isPromotionUser": "boolean",
- "username": "string",
- "chips": "integer"
+ "code": 400,
+ "message": "Insufficient balance for parent user",
+ "data": {
+ "status": "insufficient_balance",
+ "balance": 500
+ }
}
```
-**Response:**
+## Dice Data and Manage Chips API
-- **200 OK**: If the data is successfully processed.
+Handles the dice game data and manages the chips for parent and child users.
- ```json
- {
- "success": true
- }
- ```
+### Endpoint
-- **400 Bad Request**: If there is an error processing the data.
+`POST /chubgame/v1/send`
- ```json
- {
- "error": "Error message"
- }
- ```
+### Parameters
+
+- `diceAmount` (int): The amount of dice rolled.
+- `totalPoints` (int): The total points scored.
+- `promotionCode` (string): The promotion code used.
+- `isPromotionUser` (bool): Indicates if the user is a promotion user.
+- `username` (string): The username of the user.
+- `chips` (int): The number of chips of the current user.
+
+### Response
+
+#### Success
+
+```json
+{
+ "code" => 200,
+ "message" => "Game processed successfully",
+ "data" => {
+ "status" => "success",
+ "balance" => 1000
+ }
+}
+```
+
+#### Error
+
+```json
+{
+ "code": 400,
+ "message": "This promotion code has already been used",
+ "data": {
+ "status": "promotion_used"
+ }
+}
+```
## Milestone
diff --git a/src/App.jsx b/src/App.jsx
index 7989ee8..792f824 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -13,6 +13,7 @@ import { FaCopy, FaInfoCircle, FaCoins, FaArrowLeft, FaPlay, FaForward, FaTimes,
const VALIDATE_PROMOTION_CODE_API = import.meta.env.VITE_VALIDATE_PROMOTION_CODE_API;
const SEND_DICE_DATA_API = import.meta.env.VITE_SEND_DICE_DATA_API;
+const CHECK_BALANCE_API = import.meta.env.VITE_CHECK_BALANCE_API;
const MAX_DICE_AMOUNT = parseInt(import.meta.env.VITE_MAX_DICE_AMOUNT, 10); // Parsing as an integer
const App = () => {
@@ -129,7 +130,7 @@ const App = () => {
setShowChipsDialog(true);
};
- // TODO: We need to add the api endpoint in the wordpress backend
+ // We need to add the api endpoint in the wordpress backend
const sendDiceData = async (diceAmount, totalPoints, promotionCode, isPromotionUser, chips) => {
try {
const response = await fetch(SEND_DICE_DATA_API, {
@@ -148,22 +149,23 @@ const App = () => {
});
const data = await response.json();
if (!response.ok) {
- throw new Error(data.error || 'Error sending data');
+ return { success: false, message: data.message || 'Error sending data' };
}
console.log('Response from backend:', data);
+ return { success: true, data };
} catch (error) {
console.error('Error sending data to backend:', error);
- throw error;
+ return { success: false, message: error.message || 'Error sending data' };
}
};
const validatePromotionCode = async (code) => {
const regex = /^[a-zA-Z0-9]{16}$/;
if (!code) {
- return 'Promotion code cannot be empty';
+ return { valid: false, message: 'Promotion code is required' };
}
if (!regex.test(code)) {
- return 'Promotion code must be 16 characters long and contain only letters and numbers';
+ return { valid: false, message: 'Promotion code must be 16 characters long and contain only letters and numbers' };
}
try {
@@ -176,21 +178,23 @@ const App = () => {
});
const data = await response.json();
if (!response.ok) {
- throw new Error(data.error || 'Error validating promotion code');
+ return { valid: false, message: data.message || 'Error validating promotion code' };
}
- if (!data.valid) {
- return 'Invalid promotion code';
+ if (data.message != 'success' && !data.data.valid) {
+ return { valid: false, message: 'Invalid promotion code' };
}
+ console.log('Response from backend:', data);
+ return { valid: true };
} catch (error) {
console.error('Error validating promotion code:', error);
- return 'Error validating promotion code';
+ return { valid: false, message: 'Error validating promotion code' };
}
- return '';
};
const handleSubmitPromotion = async () => {
- const error = await validatePromotionCode(promotionCode);
- if (error) {
+ const result = await validatePromotionCode(promotionCode);
+ if (!result.valid) {
+ console.error('Error validating promotion code:', result.message);
setErrorPopup(error);
setTimeout(() => setErrorPopup(''), 3000); // Hide error popup after 3 seconds
return;
@@ -200,24 +204,55 @@ const App = () => {
setShowChipsDialog(true);
};
- const handlePlay = () => {
+ const validateAccountBalance = async (username, chips) => {
+ try {
+ const response = await fetch(CHECK_BALANCE_API, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ username, chips }),
+ });
+ const data = await response.json();
+ if (!response.ok) {
+ return { valid: false, message: data.message || 'Error checking balance' };
+ }
+ if (data.data.status !== 'success') {
+ return { valid: false, message: 'Insufficient balance' };
+ }
+ console.log('Response from backend:', data);
+ return { valid: true, balance: data.data.balance };
+ } catch (error) {
+ console.error('Error checking balance:', error);
+ return { valid: false, message: 'Error checking balance' };
+ }
+ };
+
+ const handlePlay = async () => {
+ const chips = selectedChips || customChips;
+ const result = await validateAccountBalance(username, chips);
+ if (!result.valid) {
+ console.error(result.message);
+ setErrorPopup(result.message);
+ return;
+ }
setShowChipsDialog(false);
// Start the game with the selected/customized chips
- console.log('Selected Chips:', selectedChips || customChips);
+ console.log('Selected Chips:', chips);
};
const handleGenerate = async () => {
- try {
- // Determine the chips to use
- const chips = customChips !== '' ? parseInt(customChips, 10) : parseInt(selectedChips, 10);
- await sendDiceData(diceAmount, totalPoints, promotionCode, true, chips);
- setSuccessPopup('Promotion code submitted successfully');
- setTimeout(() => setSuccessPopup(''), 3000); // Hide success popup after 3 seconds
- } catch (error) {
- console.error('Error saving promotion code:', error);
- setErrorPopup('Error saving promotion code');
+ // Determine the chips to use
+ const chips = customChips !== '' ? parseInt(customChips, 10) : parseInt(selectedChips, 10);
+ const result = await sendDiceData(diceAmount, totalPoints, promotionCode, true, username, chips);
+ if (!result.success) {
+ console.error('Error saving promotion code:', result.message);
+ setErrorPopup(result.message);
setTimeout(() => setErrorPopup(''), 3000); // Hide error popup after 3 seconds
+ return;
}
+ setSuccessPopup('Promotion code submitted successfully');
+ setTimeout(() => setSuccessPopup(''), 3000); // Hide success popup after 3 seconds
};
const handleSubmit = async () => {
@@ -228,17 +263,17 @@ const App = () => {
};
const handleSave = async () => {
- try {
- // Determine the chips to use
- const chips = customChips !== '' ? parseInt(customChips, 10) : parseInt(selectedChips, 10);
- await sendDiceData(diceAmount, totalPoints, promotionCode, false, chips);
- setSuccessPopup('Promotion code submitted successfully');
- setTimeout(() => setSuccessPopup(''), 3000); // Hide success popup after 3 seconds
- } catch (error) {
+ // Determine the chips to use
+ const chips = customChips !== '' ? parseInt(customChips, 10) : parseInt(selectedChips, 10);
+ const result = await sendDiceData(diceAmount, totalPoints, promotionCode, false, chips);
+ if (!result.success) {
console.error('Error submitting promotion code:', error);
setErrorPopup('Error submitting promotion code');
setTimeout(() => setErrorPopup(''), 3000); // Hide error popup after 3 seconds
+ return;
}
+ setSuccessPopup('Promotion code submitted successfully');
+ setTimeout(() => setSuccessPopup(''), 3000); // Hide success popup after 3 seconds
};
const closePopup = () => {
@@ -397,7 +432,7 @@ const App = () => {
>
- Dice Regulation
+ Game Regulation