Create New Tile Order

For Customer: **Suman**

Order Summary ๐Ÿงพ

**0 Boxes** (0 Tiles) / **โ‚น 0.00**


Area Breakdown:
**Floor Area:** 0.00 sq.ft. | **Wall Area:** 0.00 sq.ft.

`); // Event listener for room name update block.find('[name="room_name[]"]').keyup(function() { block.find('.card-title').text($(this).val() || 'New Room'); }); return block; }; $(document).ready(function(){ // --- Initial Load Logic --- const roomsContainer = $('#rooms_container'); // Load existing/default data if (Array.isArray(initial_rooms_data) && initial_rooms_data.length > 0) { initial_rooms_data.forEach(room_data => { const roomBlock = generateRoomBlock(room_data); const tileContainer = roomBlock.find('.tile-blocks-container'); const tiles = Array.isArray(room_data.tiles) ? room_data.tiles : []; tiles.forEach(tile_data => { if (!tile_data.tile_placement) { tile_data.tile_placement = 'floor'; } const tileBlock = generateTileBlock(tile_data); tileContainer.append(tileBlock); tileBlock.find('[name="cost_basis[]"]').trigger('change'); }); roomsContainer.append(roomBlock); updateRoomArea(roomBlock); }); } else { // Fallback for empty data const defaultRoomData = {"room_name":"Living Room","length_ft":"","length_in":"","width_ft":"","width_in":"","height_ft":"","height_in":"","direct_area_sqft":"","direct_wall_area_sqft":"","floor_area":100,"wall_area":112,"tiles":[{"tile_name":"Standard Floor Tile","tile_placement":"floor","t_length_ft":"","t_length_in":"0","t_width_ft":"","t_width_in":"0","tile_area_sqft":1,"tiles_per_box":"","cost_basis":"per_box","tile_cost":""}]}; const defaultRoom = generateRoomBlock(defaultRoomData); const defaultTile = generateTileBlock(defaultRoomData.tiles[0]); defaultRoom.find('.tile-blocks-container').append(defaultTile); roomsContainer.append(defaultRoom); defaultTile.find('[name="cost_basis[]"]').trigger('change'); updateRoomArea(defaultRoom); } updateGlobalSummary(); // Final calculation refresh // --- Dynamic Handlers --- // 1. Add Room $('#add_room_btn').click(function() { const newRoomData = { room_name: 'New Room ' + ($('.room-block').length + 1), length_ft: '10', width_ft: '10', height_ft: '8', direct_area_sqft: '', direct_wall_area_sqft: '', floor_area: 100.00, wall_area: 112.00 }; const newRoom = generateRoomBlock(newRoomData); const newTile = generateTileBlock({tile_placement: 'floor'}); newRoom.find('.tile-blocks-container').append(newTile); roomsContainer.append(newRoom); newTile.find('[name="cost_basis[]"]').trigger('change'); updateRoomArea(newRoom); }); // 2a/2b. Add Tile buttons roomsContainer.on('click', '.add_floor_tile_btn', function() { const tileContainer = $(this).siblings('.tile-blocks-container'); const newTile = generateTileBlock({tile_placement: 'floor'}); tileContainer.append(newTile); newTile.find('[name="cost_basis[]"]').trigger('change'); }); roomsContainer.on('click', '.add_wall_tile_btn', function() { const tileContainer = $(this).siblings('.tile-blocks-container'); const newTile = generateTileBlock({tile_placement: 'wall'}); tileContainer.append(newTile); newTile.find('[name="cost_basis[]"]').trigger('change'); }); // 3/4. Delete Room/Tile roomsContainer.on('click', '.delete_room_btn', function() { if ($('.room-block').length > 1) { if (confirm("Are you sure you want to delete this room and all its tile calculations?")) { $(this).closest('.room-block').remove(); updateGlobalSummary(); } } else { alert("You must have at least one room."); } }); roomsContainer.on('click', '.delete_tile_btn', function() { const tileBlock = $(this).closest('.tile-block'); const roomBlock = tileBlock.closest('.room-block'); if (roomBlock.find('.tile-block').length > 1) { if (confirm("Are you sure you want to delete this tile type?")) { tileBlock.remove(); updateGlobalSummary(); } } else { alert("Each room must have at least one tile type specified."); } }); // 5. Dimension/Calculation Change (Master Listener) roomsContainer.on('input change', '.calculate', function() { const block = $(this).closest('.room-block'); // If the change is in a room dimension/area input (Direct Area, L, W, or H) if (block.has(this) && ($(this).attr('name').includes('length') || $(this).attr('name').includes('width') || $(this).attr('name').includes('height') || $(this).attr('name').includes('direct_area_sqft') || $(this).attr('name').includes('direct_wall_area_sqft'))) { updateRoomArea(block); } // If the change is in a tile dimension/cost input if ($(this).closest('.tile-block').length) { updateTileCalculations($(this).closest('.tile-block')); } }); // 6. Form Submission (COMPLETED BLOCK) $('#order-form').submit(function(e){ e.preventDefault(); var _this = $(this); var el = $('
').addClass('alert alert-danger p-1 rounded-0').hide(); _this.find('.alert').remove(); const rooms_data = []; let validation_failed = false; // --- Validation Loop & Data Aggregation --- $('.room-block').each(function() { if (validation_failed) return false; const roomBlock = $(this); const room_name = roomBlock.find('[name="room_name[]"]').val(); const direct_area = roomBlock.find('[name="direct_area_sqft[]"]').val(); const direct_wall_area = roomBlock.find('[name="direct_wall_area_sqft[]"]').val(); // 1. Room Name Validation if (!room_name.trim()) { alert("Please provide a name for all rooms."); roomBlock.find('[name="room_name[]"]').focus(); validation_failed = true; return false; } const room_l_ft = roomBlock.find('[name="length_ft[]"]').val(); const room_w_ft = roomBlock.find('[name="width_ft[]"]').val(); const room_h_ft = roomBlock.find('[name="height_ft[]"]').val(); // 2. Floor Area Validation if(parseFloat(direct_area) <= 0 && (!room_l_ft || parseFloat(room_l_ft) <= 0 || !room_w_ft || parseFloat(room_w_ft) <= 0)) { alert(`Please enter a Direct Floor Area or valid Length (ft) and Width (ft) for room: ${room_name}`); roomBlock.find('[name="direct_area_sqft[]"]').focus(); validation_failed = true; return false; } // 3. Wall Area Validation: If wall tiles are requested, ensure area calculation data exists. const hasWallTiles = roomBlock.find('[name="tile_placement[]"][value="wall"]').length > 0; if (hasWallTiles && parseFloat(direct_wall_area) <= 0 && (!room_h_ft || parseFloat(room_h_ft) <= 0)) { alert(`Room '${room_name}' requires wall area for wall tiles. Please enter a Direct Wall Area or a valid Height (ft).`); roomBlock.find('[name="direct_wall_area_sqft[]"]').focus(); validation_failed = true; return false; } // 4. Tile Data Aggregation const room_tiles = []; roomBlock.find('.tile-block').each(function() { const tileBlock = $(this); // Basic Tile Validation: Cost and Tiles per Box are required if(!tileBlock.find('[name="tile_cost[]"]').val() || !tileBlock.find('[name="tiles_per_box[]"]').val()) { alert(`Tile details are incomplete in room: ${room_name}. Please check the tile cost and boxes per tile.`); validation_failed = true; return false; } room_tiles.push({ // Dimensions and Costing inputs tile_name: tileBlock.find('[name="tile_name[]"]').val(), tile_placement: tileBlock.find('[name="tile_placement[]"]').val(), t_length_ft: tileBlock.find('[name="t_length_ft[]"]').val(), t_length_in: tileBlock.find('[name="t_length_in[]"]').val(), t_width_ft: tileBlock.find('[name="t_width_ft[]"]').val(), t_width_in: tileBlock.find('[name="t_width_in[]"]').val(), tiles_per_box: tileBlock.find('[name="tiles_per_box[]"]').val(), cost_basis: tileBlock.find('[name="cost_basis[]"]').val(), tile_cost: tileBlock.find('[name="tile_cost[]"]').val(), // Calculated data (stored in data attributes) tile_area_sqft: tileBlock.data('tile_area_sqft'), total_boxes: tileBlock.data('total_boxes'), total_cost: tileBlock.data('total_cost'), total_tiles: tileBlock.data('total_tiles'), }); }); if (validation_failed) return false; // 5. Aggregated Room Data Push rooms_data.push({ room_name: room_name, // Dimension Inputs length_ft: roomBlock.find('[name="length_ft[]"]').val(), length_in: roomBlock.find('[name="length_in[]"]').val(), width_ft: roomBlock.find('[name="width_ft[]"]').val(), width_in: roomBlock.find('[name="width_in[]"]').val(), height_ft: roomBlock.find('[name="height_ft[]"]').val(), height_in: roomBlock.find('[name="height_in[]"]').val(), // Direct Area Inputs (NEW and existing) direct_area_sqft: direct_area, direct_wall_area_sqft: direct_wall_area, // Calculated Areas floor_area: roomBlock.data('floor_area'), wall_area: roomBlock.data('wall_area'), // Tiles Array tiles: room_tiles }); }); if (validation_failed) return false; // 7. Finalize Data for AJAX // Move the aggregated complex data into the hidden form field $('#hidden_rooms_data').val(JSON.stringify(rooms_data)); // 8. Send Data via AJAX _this.find('button').attr('disabled', true); $.ajax({ url:'../classes/Master.php?f=save_order', data: new FormData($(this)[0]), cache: false, contentType: false, processData: false, method: 'POST', type: 'POST', dataType: 'json', error:err=>{ console.log(err) // Use 'start_load()' and 'end_load()' if defined in your system alert("An error occurred. Check the console for details."); _this.find('button').attr('disabled', false); }, success:function(resp){ if(typeof resp =='object' && resp.status == 'success'){ // Redirect on success location.replace("./?page=tiles/view_order&id="+resp.id) }else if(resp.status == 'failed' && resp.msg != ''){ el.text(resp.msg) _this.prepend(el) $('html, body').animate({scrollTop: _this.offset().top},'fast'); }else{ alert("An unknown error occurred on the server."); console.log(resp) } _this.find('button').attr('disabled', false); } }) }) });