<?php /** * Create a ZIP of every attachment in a "Documents" CPT, * organized into main folders and sub-folders using your exact labels, * with "/" replaced by "-" in folder names, * and named after the document’s title. */ function create_documents_zip( $post_id ) { if ( ! $post_id ) { return false; } // Build ZIP filename from post title $post_title = get_the_title( $post_id ); $slug = sanitize_title( $post_title ); $zip_name = "{$slug}.zip"; // 1) Define main folders (sections) and sub-folders (fields) $sections = [ 'Personal Information' => [ 'passport-sized-photo' => 'Passport Sized Photo', 'valid-passport' => 'Valid Passport', 'national-identity-cards' => 'National Identity Cards', 'employment-pass-s-pass-dependent-pass' => 'Employment Pass/ S Pass/ Dependent Pass', 'birth-certificates-household-registration' => 'Birth Certificates/ Household Registration', 'official-marriage-certificate' => 'Official Marriage Certificate', ], 'Education & Professional Information' => [ 'education-certificates-transcripts' => 'Education Certificates/ Transcripts', 'child039schildren039s-school-admission-letter-results' => "Child's/Children's School Admission Letter/ Results", 'additional-certifications-courses-workshops' => 'Additional Certifications/ Courses/ Workshops', ], 'Social Contributions' => [ 'media-article-s-in-company--newsletters-websites--magazines--showcasing-contributions' => 'Media article (s) in Company / Newsletters / Websites / Magazines / Showcasing Contributions', 'membership-in-clubs--societies' => 'Membership in Clubs / Societies', 'charity-contribution-receipts--letters' => 'Charity Contribution Receipt(s) / Letter(s)', 'corporate-social-responsibility--community-participated-events' => 'Corporate Social Responsibility / Community Participated Events', ], 'Employment Documents' => [ 'latest-6-months-payslips' => 'Latest 6 Months Payslips', 'valid-business-registration-certificate-acrabizfile' => 'Valid Business Registration Certificate (ACRABizfile)', 'current-employer039s-letter-stating-date-of-employment-position-held-and-salary-per-month-for-past-6-months' => "Current Employer's Letter Stating Date of Employment, Position Held and Salary Per Month for Past 6 Months", 'up-to-date-resume' => 'Up To Date Resume', 'salary-increment-letters--promotion-letter-s' => 'Salary Increment Letter(s) / Promotion Letter (s)', 'annex-a-of-form-4a' => 'Annex A of Form 4A', ], 'Economic Contributions' => [ 'summary-of-personal-insurance' => 'Summary of Personal Insurance', 'summary-of-portfolio-of-personal-investments' => 'Summary of Portfolio of Personal Investments', 'summary-of-property-investments' => 'Summary of Property Investments', ], 'Testimonials' => [ 'testimonial-from-current--previous-employer' => 'Testimonial from Current / Previous Employer', 'testimonial-from-others' => 'Testimonial from Others', ], // "Additional Documents" repeater handled below only if it has files ]; // Prepare the ZIP archive $upload_dir = wp_upload_dir(); $zip_path = trailingslashit( $upload_dir['basedir'] ) . $zip_name; $zip = new ZipArchive(); if ( $zip->open( $zip_path, ZipArchive::CREATE | ZipArchive::OVERWRITE ) !== true ) { return false; } // Helper: add one file into Main/Sub $add_file = function( $att_id, $main_label, $sub_label ) use ( $zip ) { $file = get_attached_file( $att_id ); if ( ! $file || ! file_exists( $file ) ) { return; } // Clean up labels, replace "/" with "-" $safe_main = sanitize_file_name( str_replace( '/', '-', $main_label ) ); $safe_sub = sanitize_file_name( str_replace( '/', '-', $sub_label ) ); // Create the folders and add the file $zip->addEmptyDir( $safe_main ); $zip->addEmptyDir( "{$safe_main}/{$safe_sub}" ); $zip->addFile( $file, "{$safe_main}/{$safe_sub}/" . basename( $file ) ); }; // 2) Loop each defined section and its fields foreach ( $sections as $main_label => $fields ) { foreach ( $fields as $meta_key => $sub_label ) { $raw = get_post_meta( $post_id, $meta_key, true ); if ( empty( $raw ) ) { continue; } // Normalize to array of items $items = is_array( $raw ) ? $raw : ( strpos( $raw, ',' ) !== false ? array_map( 'trim', explode( ',', $raw ) ) : [ $raw ] ); foreach ( $items as $item ) { if ( is_array( $item ) && ! empty( $item['id'] ) ) { $item = $item['id']; } if ( is_string( $item ) && filter_var( $item, FILTER_VALIDATE_URL ) ) { $item = attachment_url_to_postid( $item ); } $att_id = intval( $item ); if ( $att_id ) { $add_file( $att_id, $main_label, $sub_label ); } } } } // 3) Handle the repeater field "upload-additional-documents" only if it has items $repeater = get_post_meta( $post_id, 'upload-additional-documents', true ); if ( is_array( $repeater ) && ! empty( $repeater ) ) { foreach ( $repeater as $row ) { $sub_label_raw = ! empty( $row['document-about'] ) ? $row['document-about'] : 'Miscellaneous'; $raw_items = $row['select-documents']; if ( empty( $raw_items ) ) { continue; } // Normalize repeater gallery values $items = is_array( $raw_items ) ? $raw_items : ( strpos( $raw_items, ',' ) !== false ? array_map( 'trim', explode( ',', $raw_items ) ) : [ $raw_items ] ); foreach ( $items as $item ) { if ( is_array( $item ) && ! empty( $item['id'] ) ) { $item = $item['id']; } if ( is_string( $item ) && filter_var( $item, FILTER_VALIDATE_URL ) ) { $item = attachment_url_to_postid( $item ); } $att_id = intval( $item ); if ( $att_id ) { $add_file( $att_id, 'Additional Documents', $sub_label_raw ); } } } } $zip->close(); return $zip_path; } /** * Stream the ZIP when ?download_all=1&post_id=… is requested. */ add_action( 'template_redirect', function() { if ( isset( $_GET['download_all'], $_GET['post_id'] ) ) { $post_id = intval( $_GET['post_id'] ); // Optional: verify nonce or user capability here $zip_file = create_documents_zip( $post_id ); if ( ! $zip_file || ! file_exists( $zip_file ) ) { wp_die( 'Unable to generate ZIP.' ); } header( 'Content-Type: application/zip' ); header( 'Content-Disposition: attachment; filename="' . basename( $zip_file ) . '"' ); header( 'Content-Length: ' . filesize( $zip_file ) ); readfile( $zip_file ); exit; } });
wget -nc https://dl.winehq.org/wine-builds/winehq.key
import React, { useState, useCallback, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { McButton, McInput, McMultiSelect, McSelect } from '@maersk-global/mds-react-wrapper'; import { McOption } from '@maersk-global/mds-react-wrapper/components-core/mc-option'; import styles from '../styles/CreateRule.module.css'; import data from '../data/PnLGroup.json'; class ErrorBoundary extends React.Component { state = { hasError: false }; static getDerivedStateFromError() { return { hasError: true }; } render() { if (this.state.hasError) { return <div>Something went wrong. Please refresh the page.</div>; } return this.props.children; } } const CreateRules = () => { const navigate = useNavigate(); const [activeTab, setActiveTab] = useState('ruleInfo'); const [isLoading, setIsLoading] = useState(false); const [ruleData, setRuleData] = useState({ num: '', name: '', desc: '', custRefID: '', ruleGroup: '', isActive: 'Y', pnlGroup: '', }); const [steps, setSteps] = useState([ { stepNo: '', stepName: 'Single Step', stepDesc: '', stepType: 'S', preAggregatorColumns: [], sourceTableID: '', sourceFilterSets: [{ filters: [], operator: '', values: [] }], joinColumns: [], allocationColumns: [], driverTableID: '', driverWeightColumn: '', driverFilterSets: [{ filters: [], operator: '', values: [] }], }, ]); const [errors, setErrors] = useState({ rule: {}, steps: [{ sourceFilterSets: [{}], driverFilterSets: [{}] }] }); const pnLGroups = data.PnLGroups && typeof data.PnLGroups === 'object' ? Object.keys(data.PnLGroups) : []; const ruleGroups = ruleData.pnlGroup && data.PnLGroups[ruleData.pnlGroup] ? data.PnLGroups[ruleData.pnlGroup].RuleGroups || [] : []; const sourceFilterOptions = [ { value: 'Source_Filter_1', label: 'Source Filter 1' }, { value: 'Source_Filter_2', label: 'Source Filter 2' }, { value: 'Source_Filter_3', label: 'Source Filter 3' }, ]; const sourceValueOptions = [ { value: 'Source_Value_1', label: 'Source Value 1' }, { value: 'Source_Value_2', label: 'Source Value 2' }, { value: 'Source_Value_3', label: 'Source Value 3' }, ]; const preAggregatorOptions = [ { value: 'column1', label: 'Column 1' }, { value: 'column2', label: 'Column 2' }, { value: 'column3', label: 'Column 3' }, ]; const joinColumnsOptions = [ { value: 'join_col1', label: 'Join Column 1' }, { value: 'join_col2', label: 'Join Column 2' }, { value: 'join_col3', label: 'Join Column 3' }, ]; const allocationColumnsOptions = [ { value: 'alloc_col1', label: 'Allocation Column 1' }, { value: 'alloc_col2', label: 'Allocation Column 2' }, { value: 'alloc_col3', label: 'Allocation Column 3' }, ]; const driverFilterOptions = [ { value: 'Driver_Type_1', label: 'Driver Type: Type 1' }, { value: 'Driver_Type_2', label: 'Driver Type: Type 2' }, { value: 'Driver_Status_Active', label: 'Driver Status: Active' }, ]; const driverValueOptions = [ { value: 'Driver_Value_1', label: 'Driver Value 1' }, { value: 'Driver_Value_2', label: 'Driver Value 2' }, { value: 'Driver_Value_3', label: 'Driver Value 3' }, ]; const operatorOptions = useMemo(() => [ { value: 'IN', label: 'IN' }, { value: 'NOT IN', label: 'NOT IN' }, { value: 'EQ', label: 'EQ' }, { value: 'NTEQ', label: 'NTEQ' }, { value: 'IS NULL', label: 'IS NULL' }, { value: 'GT', label: 'GT' }, { value: 'LT', label: 'LT' }, { value: 'GTEQ', label: 'GTEQ' }, { value: 'LTEQ', label: 'LTEQ' }, { value: 'BETWEEN', label: 'BETWEEN' }, { value: 'NOT BETWEEN', label: 'NOT BETWEEN' }, { value: 'LIKE', label: 'LIKE' }, ], []); const addStep = useCallback(() => { setSteps((prevSteps) => [ ...prevSteps, { stepNo: '', stepName: 'Single Step', stepDesc: '', stepType: 'S', preAggregatorColumns: [], sourceTableID: '', sourceFilterSets: [{ filters: [], operator: '', values: [] }], joinColumns: [], allocationColumns: [], driverTableID: '', driverWeightColumn: '', driverFilterSets: [{ filters: [], operator: '', values: [] }], }, ]); setErrors((prevErrors) => ({ ...prevErrors, steps: [...prevErrors.steps, { sourceFilterSets: [{}], driverFilterSets: [{}] }], })); }, []); const removeStep = useCallback((index) => { if (steps.length === 1) { alert('At least one step is required.'); return; } setSteps((prevSteps) => prevSteps.filter((_, i) => i !== index)); setErrors((prevErrors) => ({ ...prevErrors, steps: prevErrors.steps.filter((_, i) => i !== index), })); }, [steps.length]); const addFilterSet = useCallback((stepIndex, type) => { setSteps((prevSteps) => { const newSteps = [...prevSteps]; const filterKey = type === 'source' ? 'sourceFilterSets' : 'driverFilterSets'; newSteps[stepIndex] = { ...newSteps[stepIndex], [filterKey]: [...newSteps[stepIndex][filterKey], { filters: [], operator: '', values: [] }], }; return newSteps; }); setErrors((prevErrors) => { const newStepsErrors = [...prevErrors.steps]; const filterErrorsKey = type === 'source' ? 'sourceFilterSets' : 'driverFilterSets'; newStepsErrors[stepIndex] = { ...newStepsErrors[stepIndex], [filterErrorsKey]: [...newStepsErrors[stepIndex][filterErrorsKey], {}], }; return { ...prevErrors, steps: newStepsErrors }; }); }, []); const removeFilterSet = useCallback((stepIndex, filterIndex, type) => { setSteps((prevSteps) => { const newSteps = [...prevSteps]; const filterKey = type === 'source' ? 'sourceFilterSets' : 'driverFilterSets'; newSteps[stepIndex] = { ...newSteps[stepIndex], [filterKey]: newSteps[stepIndex][filterKey].filter((_, i) => i !== filterIndex), }; return newSteps; }); setErrors((prevErrors) => { const newStepsErrors = [...prevErrors.steps]; const filterErrorsKey = type === 'source' ? 'sourceFilterSets' : 'driverFilterSets'; newStepsErrors[stepIndex] = { ...newStepsErrors[stepIndex], [filterErrorsKey]: newStepsErrors[stepIndex][filterErrorsKey].filter((_, i) => i !== filterIndex), }; return { ...prevErrors, steps: newStepsErrors }; }); }, []); const validateForm = useCallback(() => { try { const newErrors = { rule: {}, steps: steps.map(() => ({ sourceFilterSets: [], driverFilterSets: [] })) }; let isValid = true; if (!ruleData.num) { newErrors.rule.num = 'Rule Number is required'; isValid = false; } else if (!/^[a-zA-Z0-9]+$/.test(ruleData.num)) { newErrors.rule.num = 'Rule Number must be alphanumeric'; isValid = false; } if (!ruleData.name) { newErrors.rule.name = 'Rule Name is required'; isValid = false; } if (!ruleData.desc) { newErrors.rule.desc = 'Description is required'; isValid = false; } if (!ruleData.custRefID) { newErrors.rule.custRefID = 'Customer Reference ID is required'; isValid = false; } if (!ruleData.pnlGroup) { newErrors.rule.pnlGroup = 'PnL Group is required'; isValid = false; } if (!ruleData.ruleGroup) { newErrors.ruleGroup = 'Rule Group is required'; isValid = false; } if (!ruleData.isActive) { newErrors.rule.isActive = 'Active status is required'; isValid = false; } const stepNumbers = new Set(); steps.forEach((step, index) => { const stepErrors = { sourceFilterSets: step.sourceFilterSets.map(() => ({})), driverFilterSets: step.driverFilterSets.map(() => ({})) }; if (!step.stepNo) { stepErrors.stepNo = 'Step Number is required'; isValid = false; } else if (stepNumbers.has(step.stepNo)) { stepErrors.stepNo = 'Step Number must be unique'; isValid = false; } else { stepNumbers.add(step.stepNo); } if (!step.stepName) { stepErrors.stepName = 'Step Name is required'; isValid = false; } if (!step.stepDesc) { stepErrors.stepDesc = 'Step Description is required'; isValid = false; } if (!step.stepType) { stepErrors.stepType = 'Step Type is required'; isValid = false; } if (!step.preAggregatorColumns.length) { stepErrors.preAggregatorColumns = 'Pre-Aggregator Columns is required'; isValid = false; } if (!step.sourceTableID) { stepErrors.sourceTableID = 'Source Table ID is required'; isValid = false; } if (!step.sourceFilterSets.some(set => set.filters.length && set.operator && set.values.length)) { stepErrors.sourceFilterSets[0].filters = 'At least one complete Source Filter set is required'; isValid = false; } step.sourceFilterSets.forEach((set, filterIndex) => { if (set.filters.length || set.operator || set.values.length) { if (!set.filters.length) { stepErrors.sourceFilterSets[filterIndex].filters = 'Source Filters is required'; isValid = false; } if (!set.operator) { stepErrors.sourceFilterSets[filterIndex].operator = 'Source Operator is required'; isValid = false; } if (!set.values.length) { stepErrors.sourceFilterSets[filterIndex].values = 'Source Values is required'; isValid = false; } } }); if (!step.joinColumns.length) { stepErrors.joinColumns = 'Join Columns is required'; isValid = false; } if (!step.allocationColumns.length) { stepErrors.allocationColumns = 'Allocation Columns is required'; isValid = false; } if (!step.driverTableID) { stepErrors.driverTableID = 'Driver Table ID is required'; isValid = false; } if (!step.driverWeightColumn) { stepErrors.driverWeightColumn = 'Driver Weight Column is required'; isValid = false; } if (!step.driverFilterSets.some(set => set.filters.length && set.operator && set.values.length)) { stepErrors.driverFilterSets[0].filters = 'At least one complete Driver Filter set is required'; isValid = false; } step.driverFilterSets.forEach((set, filterIndex) => { if (set.filters.length || set.operator || set.values.length) { if (!set.filters.length) { stepErrors.driverFilterSets[filterIndex].filters = 'Driver Filters is required'; isValid = false; } if (!set.operator) { stepErrors.driverFilterSets[filterIndex].operator = 'Driver Operator is required'; isValid = false; } if (!set.values.length) { stepErrors.driverFilterSets[filterIndex].values = 'Driver Values is required'; isValid = false; } } }); newErrors.steps[index] = stepErrors; }); setErrors(newErrors); return isValid; } catch (error) { alert('An error occurred during form validation. Please try again.'); return false; } }, [ruleData, steps]); const parseColumns = (input) => input; const parseFilters = (filterSets) => { return filterSets .filter(set => set.filters.length && set.operator && set.values.length) .map(set => ({ name: set.filters, filterType: set.operator, values: set.values, })); }; const handleInputChange = useCallback((e, stepIndex = null) => { const { name, value } = e.target; if (stepIndex !== null) { setSteps((prevSteps) => { const newSteps = [...prevSteps]; newSteps[stepIndex] = { ...newSteps[stepIndex], [name]: value }; return newSteps; }); setErrors((prevErrors) => { const newStepsErrors = [...prevErrors.steps]; newStepsErrors[stepIndex] = { ...newStepsErrors[stepIndex], [name]: '', }; return { ...prevErrors, steps: newStepsErrors }; }); } else { setRuleData((prevData) => ({ ...prevData, [name]: value, ...(name === 'pnlGroup' ? { ruleGroup: '' } : {}), })); setErrors((prevErrors) => ({ ...prevErrors, rule: { ...prevErrors.rule, [name]: '' }, })); } }, []); const handleFilterSetChange = useCallback((e, stepIndex, filterIndex, type, field) => { const filterKey = type === 'source' ? 'sourceFilterSets' : 'driverFilterSets'; const value = field === 'operator' ? e.target.value : e.detail.map(option => option.value); setSteps((prevSteps) => { const newSteps = [...prevSteps]; newSteps[stepIndex] = { ...newSteps[stepIndex], [filterKey]: newSteps[stepIndex][filterKey].map((set, i) => i === filterIndex ? { ...set, [field]: value } : set ), }; return newSteps; }); setErrors((prevErrors) => { const newStepsErrors = [...prevErrors.steps]; const filterErrorsKey = type === 'source' ? 'sourceFilterSets' : 'driverFilterSets'; newStepsErrors[stepIndex] = { ...newStepsErrors[stepIndex], [filterErrorsKey]: newStepsErrors[stepIndex][filterErrorsKey].map((setErrors, i) => i === filterIndex ? { ...setErrors, [field]: '' } : setErrors ), }; return { ...prevErrors, steps: newStepsErrors }; }); }, []); const resetForm = useCallback(() => { setRuleData({ num: '', name: '', desc: '', custRefID: '', ruleGroup: '', isActive: 'Y', pnlGroup: '', }); setSteps([ { stepNo: '', stepName: 'Single Step', stepDesc: '', stepType: 'S', preAggregatorColumns: [], sourceTableID: '', sourceFilterSets: [{ filters: [], operator: '', values: [] }], joinColumns: [], allocationColumns: [], driverTableID: '', driverWeightColumn: '', driverFilterSets: [{ filters: [], operator: '', values: [] }], }, ]); setErrors({ rule: {}, steps: [{ sourceFilterSets: [{}], driverFilterSets: [{}] }] }); setActiveTab('ruleInfo'); }, []); const handleSave = useCallback(async () => { if (!validateForm()) { alert('Please fill out all required fields.'); return; } setIsLoading(true); const ruleJson = { rules: { rule: [ { num: ruleData.num, name: ruleData.name, desc: ruleData.desc, custRefID: ruleData.custRefID, ruleGroup: ruleData.ruleGroup, isActive: ruleData.isActive, Step: steps.map((step, index) => ({ stepNo: step.stepNo || `${ruleData.num}.${index + 1}`, stepName: step.stepName === 'Single Step' ? 'single' : 'multi', stepDesc: step.stepDesc, stepType: step.stepType, isActive: 'Y', SourceTable: { id: step.sourceTableID, Name: step.sourceTableID, }, sourceFilters: { columns: parseFilters(step.sourceFilterSets), }, preAggregator: { columns: parseColumns(step.preAggregatorColumns), }, join: { columns: parseColumns(step.joinColumns), }, allocation: { columns: parseColumns(step.allocationColumns), }, driver: { driverTableID: step.driverTableID, driverWeightColumn: step.driverWeightColumn, driverFilters: { columns: parseFilters(step.driverFilterSets), }, }, })), }, ], }, }; const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 10000); try { const response = await fetch('/api/rules', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: JSON.stringify(ruleJson), signal: controller.signal, }); clearTimeout(timeoutId); if (response.ok) { alert('Rule created successfully!'); resetForm(); navigate('/'); } else { const errorData = await response.json().catch(() => ({ message: response.statusText })); alert(`Failed to create rule: ${errorData.message || response.statusText}`); } } catch (error) { if (error.name === 'AbortError') { alert('Request timed out. Please try again.'); } else { alert('An error occurred while saving the rule. Please try again.'); } } finally { setIsLoading(false); } }, [validateForm, ruleData, steps, resetForm, navigate]); const handleCancel = useCallback(() => { navigate('/'); }, [navigate]); const renderTabContent = () => { switch (activeTab) { case 'ruleInfo': return ( <div className={styles.tabContent}> {Object.values(errors.rule).some((error) => error) && ( <div className={styles.errorSummary}> <h4>Please fix the following errors:</h4> <ul> {Object.entries(errors.rule).map(([key, error]) => error && ( <li key={key}>{error}</li> ))} </ul> </div> )} <h3 className={styles.sectionTitle}>Rule Information</h3> <div className={styles.formGrid}> <div className={styles.gridItem}> <McSelect label="PnL Group" name="pnlGroup" value={ruleData.pnlGroup} input={handleInputChange} placeholder="Select a PnL Group" required invalid={!!errors.rule.pnlGroup} invalidmessage={errors.rule.pnlGroup} > {pnLGroups.map((group) => ( <McOption key={group} value={group}> {group} </McOption> ))} </McSelect> </div> <div className={styles.gridItem}> <McSelect label="Rule Group" name="ruleGroup" value={ruleData.ruleGroup} input={handleInputChange} placeholder={ruleGroups.length ? "Select a Rule Group" : "Select a PnL Group first"} required disabled={!ruleData.pnlGroup || !ruleGroups.length} invalid={!!errors.rule.ruleGroup} invalidmessage={errors.rule.ruleGroup} > {ruleGroups.map((group) => ( <McOption key={group} value={group}> {group} </McOption> ))} </McSelect> </div> </div> <div className={styles.inputGroup}> <McInput label="Rule Number" name="num" value={ruleData.num} input={handleInputChange} placeholder="Enter rule number" required invalid={!!errors.rule.num} invalidmessage={errors.rule.num} /> </div> <div className={styles.inputGroup}> <McInput label="Rule Name" name="name" value={ruleData.name} input={handleInputChange} placeholder="Enter rule name" required invalid={!!errors.rule.name} invalidmessage={errors.rule.name} /> </div> <div className={styles.inputGroup}> <McInput label="Description" name="desc" value={ruleData.desc} input={handleInputChange} placeholder="Enter rule description" multiline rows={3} required invalid={!!errors.rule.desc} invalidmessage={errors.rule.desc} /> </div> <div className={styles.inputGroup}> <McInput label="Customer Reference ID" name="custRefID" value={ruleData.custRefID} input={handleInputChange} placeholder="Enter customer reference ID" required invalid={!!errors.rule.custRefID} invalidmessage={errors.rule.custRefID} /> </div> </div> ); case 'step': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Step Information</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4 style={{ color: '#35B0CB' }}>STEP {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Step Number" name="stepNo" value={step.stepNo} input={(e) => handleInputChange(e, index)} placeholder={`Enter step number (e.g., ${ruleData.num}.${index + 1})`} required invalid={!!errors.steps[index].stepNo} invalidmessage={errors.steps[index].stepNo} /> </div> <div className={styles.inputGroup}> <McSelect label="Step Name" name="stepName" value={step.stepName} input={(e) => handleInputChange(e, index)} required placeholder="Select Step Name" invalid={!!errors.steps[index].stepName} invalidmessage={errors.steps[index].stepName} > <McOption value="Single Step">Single Step</McOption> <McOption value="Multi Step">Multi Step</McOption> </McSelect> </div> <div className={styles.inputGroup}> <McInput label="Step Description" name="stepDesc" value={step.stepDesc} input={(e) => handleInputChange(e, index)} placeholder="Enter step description" multiline rows={3} required invalid={!!errors.steps[index].stepDesc} invalidmessage={errors.steps[index].stepDesc} /> </div> <div className={styles.inputGroup}> <McSelect label="Step Type" name="stepType" value={step.stepType} input={(e) => handleInputChange(e, index)} required placeholder="Select Step Type" invalid={!!errors.steps[index].stepType} invalidmessage={errors.steps[index].stepType} > <McOption value="S">S</McOption> <McOption value="M">M</McOption> </McSelect> </div> </div> ))} <div className={styles.stepButtonContainer}> <McButton label="Add Step" appearance="secondary" click={addStep} className={styles.actionButton} /> {steps.length > 1 && ( <McButton label="Remove Step" appearance="neutral" click={() => removeStep(steps.length - 1)} className={styles.actionButton} /> )} </div> </div> ); case 'source': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Source Information</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4 style={{ color: '#35B0CB' }}>STEP {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Source Table ID" name="sourceTableID" value={step.sourceTableID} input={(e) => handleInputChange(e, index)} placeholder="Enter source table ID" required invalid={!!errors.steps[index].sourceTableID} invalidmessage={errors.steps[index].sourceTableID} /> </div> {step.sourceFilterSets.map((filterSet, filterIndex) => ( <div key={filterIndex} className={styles.filterRow}> <McMultiSelect label="Source Filters" name="sourceFilters" value={filterSet.filters} optionselected={(e) => handleFilterSetChange(e, index, filterIndex, 'source', 'filters')} placeholder="Select source filters" required invalid={!!errors.steps[index].sourceFilterSets[filterIndex]?.filters} invalidmessage={errors.steps[index].sourceFilterSets[filterIndex]?.filters} > {sourceFilterOptions.map((option) => ( <McOption key={option.value} value={option.value}> {option.label} </McOption> ))} </McMultiSelect> <McSelect label="Source Operator" name="sourceOperator" value={filterSet.operator} input={(e) => handleFilterSetChange(e, index, filterIndex, 'source', 'operator')} placeholder="Select an operator" required invalid={!!errors.steps[index].sourceFilterSets[filterIndex]?.operator} invalidmessage={errors.steps[index].sourceFilterSets[filterIndex]?.operator} > {operatorOptions.map((option) => ( <McOption key={option.value} value={option.value}> {option.label} </McOption> ))} </McSelect> <div className={styles.filterValueContainer}> <McMultiSelect label="Source Values" name="sourceValues" value={filterSet.values} optionselected={(e) => handleFilterSetChange(e, index, filterIndex, 'source', 'values')} placeholder="Select source values" required invalid={!!errors.steps[index].sourceFilterSets[filterIndex]?.values} invalidmessage={errors.steps[index].sourceFilterSets[filterIndex]?.values} > {sourceValueOptions.map((option) => ( <McOption key={option.value} value={option.value}> {option.label} </McOption> ))} </McMultiSelect> {step.sourceFilterSets.length > 1 && ( <McButton label="Remove" appearance="neutral" click={() => removeFilterSet(index, filterIndex, 'source')} className={styles.removeButton} /> )} </div> </div> ))} <div className={styles.stepButtonContainer}> <McButton label="Add More" appearance="secondary" click={() => addFilterSet(index, 'source')} className={styles.actionButton} /> </div> </div> ))} </div> ); case 'preAggregate': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Pre-Aggregate Columns</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4 style={{ color: '#35B0CB' }}>STEP {index + 1}</h4> <div className={styles.inputGroup}> <McMultiSelect label="Pre-Aggregator Columns" name="preAggregatorColumns" value={step.preAggregatorColumns} optionselected={(e) => handleMultiSelectChange(e, index, 'preAggregatorColumns')} placeholder="Select pre-aggregator columns" required invalid={!!errors.steps[index].preAggregatorColumns} invalidmessage={errors.steps[index].preAggregatorColumns} > {preAggregatorOptions.map((option) => ( <McOption key={option.value} value={option.value}> {option.label} </McOption> ))} </McMultiSelect> </div> </div> ))} </div> ); case 'join': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Join Columns</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4 style={{ color: '#35B0CB' }}>STEP {index + 1}</h4> <div className={styles.inputGroup}> <McMultiSelect label="Join Columns" name="joinColumns" value={step.joinColumns} optionselected={(e) => handleMultiSelectChange(e, index, 'joinColumns')} placeholder="Select join columns" required invalid={!!errors.steps[index].joinColumns} invalidmessage={errors.steps[index].joinColumns} > {joinColumnsOptions.map((option) => ( <McOption key={option.value} value={option.value}> {option.label} </McOption> ))} </McMultiSelect> </div> </div> ))} </div> ); case 'allocation': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Allocation Columns</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4 style={{ color: '#35B0CB' }}>STEP {index + 1}</h4> <div className={styles.inputGroup}> <McMultiSelect label="Allocation Columns" name="allocationColumns" value={step.allocationColumns} optionselected={(e) => handleMultiSelectChange(e, index, 'allocationColumns')} placeholder="Select allocation columns" required invalid={!!errors.steps[index].allocationColumns} invalidmessage={errors.steps[index].allocationColumns} > {allocationColumnsOptions.map((option) => ( <McOption key={option.value} value={option.value}> {option.label} </McOption> ))} </McMultiSelect> </div> </div> ))} </div> ); case 'driver': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Driver Information</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4 style={{ color: '#35B0CB' }}>STEP {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Driver Table ID" name="driverTableID" value={step.driverTableID} input={(e) => handleInputChange(e, index)} placeholder="Enter driver table ID" required invalid={!!errors.steps[index].driverTableID} invalidmessage={errors.steps[index].driverTableID} /> </div> <div className={styles.inputGroup}> <McInput label="Driver Weight Column" name="driverWeightColumn" value={step.driverWeightColumn} input={(e) => handleInputChange(e, index)} placeholder="Enter driver weight column" required invalid={!!errors.steps[index].driverWeightColumn} invalidmessage={errors.steps[index].driverWeightColumn} /> </div> {step.driverFilterSets.map((filterSet, filterIndex) => ( <div key={filterIndex} className={styles.filterRow}> <McMultiSelect label="Driver Filters" name="driverFilters" value={filterSet.filters} optionselected={(e) => handleFilterSetChange(e, index, filterIndex, 'driver', 'filters')} placeholder="Select driver filters" required invalid={!!errors.steps[index].driverFilterSets[filterIndex]?.filters} invalidmessage={errors.steps[index].driverFilterSets[filterIndex]?.filters} > {driverFilterOptions.map((option) => ( <McOption key={option.value} value={option.value}> {option.label} </McOption> ))} </McMultiSelect> <McSelect label="Driver Operator" name="driverOperator" value={filterSet.operator} input={(e) => handleFilterSetChange(e, index, filterIndex, 'driver', 'operator')} placeholder="Select an operator" required invalid={!!errors.steps[index].driverFilterSets[filterIndex]?.operator} invalidmessage={errors.steps[index].driverFilterSets[filterIndex]?.operator} > {operatorOptions.map((option) => ( <McOption key={option.value} value={option.value}> {option.label} </McOption> ))} </McSelect> <div className={styles.filterValueContainer}> <McMultiSelect label="Driver Values" name="driverValues" value={filterSet.values} optionselected={(e) => handleFilterSetChange(e, index, filterIndex, 'driver', 'values')} placeholder="Select driver values" required invalid={!!errors.steps[index].driverFilterSets[filterIndex]?.values} invalidmessage={errors.steps[index].driverFilterSets[filterIndex]?.values} > {driverValueOptions.map((option) => ( <McOption key={option.value} value={option.value}> {option.label} </McOption> ))} </McMultiSelect> {step.driverFilterSets.length > 1 && ( <McButton label="Remove" appearance="neutral" click={() => removeFilterSet(index, filterIndex, 'driver')} className={styles.removeButton} /> )} </div> </div> ))} <div className={styles.stepButtonContainer}> <McButton label="Add More" appearance="secondary" click={() => addFilterSet(index, 'driver')} className={styles.actionButton} /> </div> </div> ))} </div> ); default: return <div className={styles.tabContent}>No Tab Selected</div>; } }; return ( <ErrorBoundary> <div className={styles.pageWrapper}> {isLoading && ( <div className={styles.loader}>Loading...</div> )} <div className={styles.container}> <div className={styles.card}> <div className={styles.buttonContainer}> <McButton label="Back" appearance="neutral" click={handleCancel} className={styles.actionButton} /> <McButton label="Save" appearance="primary" click={handleSave} className={styles.actionButton} loading={isLoading} disabled={isLoading} /> </div> <div className={styles.tabs}> <button className={`${styles.tabButton} ${activeTab === 'ruleInfo' ? styles.activeTab : ''}`} onClick={() => setActiveTab('ruleInfo')} > Rule Info </button> <button className={`${styles.tabButton} ${activeTab === 'step' ? styles.activeTab : ''}`} onClick={() => setActiveTab('step')} > Step </button> <button className={`${styles.tabButton} ${activeTab === 'source' ? styles.activeTab : ''}`} onClick={() => setActiveTab('source')} > Source </button> <button className={`${styles.tabButton} ${activeTab === 'preAggregate' ? styles.activeTab : ''}`} onClick={() => setActiveTab('preAggregate')} > Pre-Aggregate </button> <button className={`${styles.tabButton} ${activeTab === 'join' ? styles.activeTab : ''}`} onClick={() => setActiveTab('join')} > Join </button> <button className={`${styles.tabButton} ${activeTab === 'allocation' ? styles.activeTab : ''}`} onClick={() => setActiveTab('allocation')} > Allocation </button> <button className={`${styles.tabButton} ${activeTab === 'driver' ? styles.activeTab : ''}`} onClick={() => setActiveTab('driver')} > Driver </button> </div> {renderTabContent()} </div> </div> </div> </ErrorBoundary> ); }; export default CreateRules;
C:\Users\"Benutzerordner"\AppData\Local\Packages\5319275A.WhatsAppDesktop_cv1g1gvanyjgm\LocalState\shared\transfers\
import React, { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { McButton, McInput, McMultiSelect } from '@maersk-global/mds-react-wrapper'; import { McSelect } from '@maersk-global/mds-react-wrapper/components-core/mc-select'; import { McOption } from '@maersk-global/mds-react-wrapper/components-core/mc-option'; import styles from '../styles/CreateRule.module.css'; import data from '../data/PnLGroup.json'; const CreateRules = () => { const navigate = useNavigate(); const [activeTab, setActiveTab] = useState('ruleInfo'); const [isLoading, setIsLoading] = useState(false); const [ruleData, setRuleData] = useState({ num: '', name: '', desc: '', custRefID: '', ruleGroup: '', isActive: 'Y', pnlGroup: '', }); const [steps, setSteps] = useState([ { stepNo: '', stepName: 'Single Step', StepDesc: '', stepType: 'S', preAggregatorColumns: '', sourceTable: '', sourceFilters: '', joinColumns: '', allocationColumns: '', driverTableID: '', driverWeightColumn: '', driverFilters: '', }, ]); const [errors, setErrors] = useState({ rule: {}, steps: [{}] }); const pnlGroups = data.PnLGroups ? Object.keys(data.PnLGroups) : []; const ruleGroups = ruleData.pnlGroup && data.PnLGroups[ruleData.pnlGroup] ? data.PnLGroups[ruleData.pnlGroup].RuleGroups || [] : []; console.log('pnlGroups:', pnlGroups); console.log('ruleGroups:', ruleGroups); const addStep = () => { setSteps((prevSteps) => [ ...prevSteps, { stepNo: '', stepName: 'Single Step', StepDesc: '', stepType: 'S', preAggregatorColumns: '', sourceTable: '', sourceFilters: '', joinColumns: '', allocationColumns: '', driverTableID: '', driverWeightColumn: '', driverFilters: '', }, ]); setErrors((prevErrors) => ({ ...prevErrors, steps: [...prevErrors.steps, {}], })); }; const removeStep = (index) => { if (steps.length === 1) { alert('At least one step is required.'); return; } setSteps((prevSteps) => prevSteps.filter((_, i) => i !== index)); setErrors((prevErrors) => ({ ...prevErrors, steps: prevErrors.steps.filter((_, i) => i !== index), })); }; const validateForm = () => { const newErrors = { rule: {}, steps: steps.map(() => ({})) }; let isValid = true; if (!ruleData.num) { newErrors.rule.num = 'Rule Number is required'; isValid = false; } else if (!/^[a-zA-Z0-9]+$/.test(ruleData.num)) { newErrors.rule.num = 'Rule Number must be alphanumeric'; isValid = false; } if (!ruleData.name) { newErrors.rule.name = 'Rule Name is required'; isValid = false; } if (!ruleData.desc) { newErrors.rule.desc = 'Description is required'; isValid = false; } if (!ruleData.custRefID) { newErrors.rule.custRefID = 'Customer Reference ID is required'; isValid = false; } if (!ruleData.pnlGroup) { newErrors.rule.pnlGroup = 'PnL Group is required'; isValid = false; } if (!ruleData.ruleGroup) { newErrors.rule.ruleGroup = 'Rule Group is required'; isValid = false; } if (!ruleData.isActive) { newErrors.rule.isActive = 'Active status is required'; isValid = false; } const stepNumbers = new Set(); steps.forEach((step, index) => { const stepErrors = {}; if (!step.stepNo) { stepErrors.stepNo = 'Step Number is required'; isValid = false; } else if (stepNumbers.has(step.stepNo)) { stepErrors.stepNo = 'Step Number must be unique'; isValid = false; } else { stepNumbers.add(step.stepNo); } if (!step.stepName) { stepErrors.stepName = 'Step Name is required'; isValid = false; } if (!step.StepDesc) { stepErrors.StepDesc = 'Step Description is required'; isValid = false; } if (!step.stepType) { stepErrors.stepType = 'Step Type is required'; isValid = false; } if (!step.preAggregatorColumns) { stepErrors.preAggregatorColumns = 'Pre-Aggregator Columns are required'; isValid = false; } if (!step.sourceTable) { stepErrors.sourceTable = 'Source Table is required'; isValid = false; } if (!step.sourceFilters) { stepErrors.sourceFilters = 'Source Filters are required'; isValid = false; } else { try { parseFilters(step.sourceFilters); } catch (e) { stepErrors.sourceFilters = 'Invalid Source Filter format'; isValid = false; } } if (!step.joinColumns) { stepErrors.joinColumns = 'Join Columns are required'; isValid = false; } if (!step.allocationColumns) { stepErrors.allocationColumns = 'Allocation Columns are required'; isValid = false; } if (!step.driverTableID) { stepErrors.driverTableID = 'Driver Table ID is required'; isValid = false; } if (!step.driverWeightColumn) { stepErrors.driverWeightColumn = 'Driver Weight Column is required'; isValid = false; } if (!step.driverFilters) { stepErrors.driverFilters = 'Driver Filters are required'; isValid = false; } else { try { parseFilters(step.driverFilters); } catch (e) { stepErrors.driverFilters = 'Invalid Driver Filter format'; isValid = false; } } newErrors.steps[index] = stepErrors; }); setErrors(newErrors); return isValid; }; const parseColumns = (input) => input.split(',').map((item) => item.trim()).filter((item) => item); const parseFilters = (input) => { if (!input) return []; const filters = input.split(';').map((item) => item.trim()).filter((item) => item); return filters.map((filter) => { const parts = filter.split(':').map((item) => item.trim()); if (parts.length !== 3) { throw new Error('Invalid filter format'); } const [name, filterType, values] = parts; if (!name || !filterType || !values) { throw new Error('Invalid filter format'); } return { name, filterType, values }; }); }; const handleInputChange = (e, stepIndex = null) => { const { name, value } = e.target; console.log(`Input changed: ${name} = ${value}${stepIndex !== null ? ` (Step ${stepIndex + 1})` : ''}`); if (stepIndex !== null) { setSteps((prevSteps) => { const newSteps = [...prevSteps]; newSteps[stepIndex] = { ...newSteps[stepIndex], [name]: value }; return newSteps; }); setErrors((prevErrors) => ({ ...prevErrors, steps: prevErrors.steps.map((stepErrors, i) => i === stepIndex ? { ...stepErrors, [name]: '' } : stepErrors ), })); } else { setRuleData((prevData) => { const newData = { ...prevData, [name]: value, ...(name === 'pnlGroup' ? { ruleGroup: '' } : {}), }; console.log('Updated ruleData:', newData); return newData; }); setErrors((prevErrors) => ({ ...prevErrors, rule: { ...prevErrors.rule, [name]: '' }, })); } }; const resetForm = () => { setRuleData({ num: '', name: '', desc: '', custRefID: '', ruleGroup: '', isActive: 'Y', pnlGroup: '', }); setSteps([ { stepNo: '', stepName: 'Single Step', StepDesc: '', stepType: 'S', preAggregatorColumns: '', sourceTable: '', sourceFilters: '', joinColumns: '', allocationColumns: '', driverTableID: '', driverWeightColumn: '', driverFilters: '', }, ]); setErrors({ rule: {}, steps: [{}] }); setActiveTab('ruleInfo'); }; const handleSave = async () => { if (!validateForm()) { console.log('Validation failed:', JSON.stringify(errors, null, 2)); alert('Please fill out all required fields.'); return; } setIsLoading(true); const ruleJson = { rules: { rule: [ { num: ruleData.num, name: ruleData.name, desc: ruleData.desc, custRefID: ruleData.custRefID, ruleGroup: ruleData.ruleGroup, isActive: ruleData.isActive, Step: steps.map((step, index) => ({ stepNo: step.stepNo || `${ruleData.num}.${index + 1}`, stepName: step.stepName === 'Single Step' ? 'single' : 'multi', StepDesc: step.StepDesc, stepType: step.stepType, isActive: 'Y', SourceTable: { id: '1', Name: step.sourceTable, }, sourceFilters: { columns: parseFilters(step.sourceFilters), }, preAggregator: { columns: parseColumns(step.preAggregatorColumns), }, join: { columns: parseColumns(step.joinColumns), }, allocation: { columns: parseColumns(step.allocationColumns), }, driver: { driverTableID: step.driverTableID, driverWeightColumn: step.driverWeightColumn, driverFilters: { columns: parseFilters(step.driverFilters), }, }, })), }, ], }, }; console.log('Saving Rule Data:', JSON.stringify(ruleJson, null, 2)); try { const response = await fetch('/api/rules', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: JSON.stringify(ruleJson), }); if (response.ok) { console.log('Rule created successfully'); alert('Rule created successfully!'); resetForm(); navigate('/'); } else { const errorData = await response.json().catch(() => ({ message: response.statusText })); console.error('Failed to create rule:', response.status, errorData); alert(`Failed to create rule: ${errorData.message || response.statusText}`); } } catch (error) { console.error('Error during API call:', error.message); alert('An error occurred while saving the rule. Please try again.'); } finally { setIsLoading(false); } }; const handleCancel = () => { console.log('Cancelling rule creation'); navigate('/'); }; const renderTabContent = () => { console.log('Rendering tab:', activeTab); switch (activeTab) { case 'ruleInfo': return ( <div className={styles.tabContent}> {Object.values(errors.rule).some((error) => error) && ( <div className={styles.errorSummary}> <h4>Please fix the following errors:</h4> <ul> {Object.entries(errors.rule).map(([key, error]) => error && ( <li key={key}>{error}</li> ))} </ul> </div> )} <h3 className={styles.sectionTitle}>Rule Information</h3> <div className={styles.formGrid}> <div className={styles.gridItem}> <McSelect label="PnL Group" name="pnlGroup" value={ruleData.pnlGroup} input={handleInputChange} placeholder="Select a PnL Group" required invalid={!!errors.rule.pnlGroup} invalidmessage={errors.rule.pnlGroup} > {pnlGroups.map((group) => ( <McOption key={group} value={group}> {group} </McOption> ))} </McSelect> </div> <div className={styles.gridItem}> <McSelect label="Rule Group" name="ruleGroup" value={ruleData.ruleGroup} input={handleInputChange} placeholder={ruleGroups.length ? "Select a Rule Group" : "Select a PnL Group first"} required disabled={!ruleData.pnlGroup || !ruleGroups.length} invalid={!!errors.rule.ruleGroup} invalidmessage={errors.rule.ruleGroup} > {ruleGroups.map((group) => ( <McOption key={group} value={group}> {group} </McOption> ))} </McSelect> </div> </div> <div className={styles.inputGroup}> <McInput label="Rule Number" name="num" value={ruleData.num} input={handleInputChange} placeholder="Enter rule number" required invalid={!!errors.rule.num} invalidmessage={errors.rule.num} /> </div> <div className={styles.inputGroup}> <McInput label="Rule Name" name="name" value={ruleData.name} input={handleInputChange} placeholder="Enter rule name" required invalid={!!errors.rule.name} invalidmessage={errors.rule.name} /> </div> <div className={styles.inputGroup}> <McInput label="Description" name="desc" value={ruleData.desc} input={handleInputChange} placeholder="Enter rule description" multiline rows={3} required invalid={!!errors.rule.desc} invalidmessage={errors.rule.desc} /> </div> <div className={styles.inputGroup}> <McInput label="Customer Reference ID" name="custRefID" value={ruleData.custRefID} input={handleInputChange} placeholder="Enter customer reference ID" required invalid={!!errors.rule.custRefID} invalidmessage={errors.rule.custRefID} /> </div> </div> ); case 'step': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Step Information</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4 style={{ color: '#35B0CB' }}>STEP {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Step Number" name="stepNo" value={step.stepNo} input={(e) => handleInputChange(e, index)} placeholder={`Enter step number (e.g., ${ruleData.num}.${index + 1})`} required invalid={!!errors.steps[index].stepNo} invalidmessage={errors.steps[index].stepNo} /> </div> <div className={styles.inputGroup}> <McSelect label="Step Name" name="stepName" value={step.stepName} input={(e) => handleInputChange(e, index)} required placeholder="Select Step Name" invalid={!!errors.steps[index].stepName} invalidmessage={errors.steps[index].stepName} > <McOption value="Single Step">Single Step</McOption> <McOption value="Multi Step">Multi Step</McOption> </McSelect> </div> <div className={styles.inputGroup}> <McInput label="Step Description" name="StepDesc" value={step.StepDesc} input={(e) => handleInputChange(e, index)} placeholder="Enter step description" multiline rows={3} required invalid={!!errors.steps[index].StepDesc} invalidmessage={errors.steps[index].StepDesc} /> </div> <div className={styles.inputGroup}> <McSelect label="Step Type" name="stepType" value={step.stepType} input={(e) => handleInputChange(e, index)} required placeholder="Select Step Type" invalid={!!errors.steps[index].stepType} invalidmessage={errors.steps[index].stepType} > <McOption value="S">S</McOption> <McOption value="M">M</McOption> </McSelect> </div> </div> ))} <div className={styles.stepButtonContainer}> <McButton label="Add Step" appearance="secondary" click={addStep} className={styles.actionButton} /> {steps.length > 1 && ( <McButton label="Remove Step" appearance="neutral" click={() => removeStep(steps.length - 1)} className={styles.actionButton} /> )} </div> </div> ); case 'source': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Source Information</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4 style={{ color: '#35B0CB' }}>STEP {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Source Table" name="sourceTable" value={step.sourceTable} input={(e) => handleInputChange(e, index)} placeholder="Enter source table name" required invalid={!!errors.steps[index].sourceTable} invalidmessage={errors.steps[index].sourceTable} /> </div> <div className={styles.inputGroup}> <McInput label="Source Filters" name="sourceFilters" value={step.sourceFilters} input={(e) => handleInputChange(e, index)} placeholder="Enter filters (e.g., PNL_LINE:IN:PnL.DVC.214,PnL.DVC.215;MOVE_TYPE:EQ:EX)" multiline rows={3} required invalid={!!errors.steps[index].sourceFilters} invalidmessage={errors.steps[index].sourceFilters} /> </div> </div> ))} </div> ); case 'preAggregate': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Pre-Aggregate Columns</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4 style={{ color: '#35B0CB' }}>STEP {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Pre-Aggregator Columns" name="preAggregatorColumns" value={step.preAggregatorColumns} input={(e) => handleInputChange(e, index)} placeholder="Enter columns (comma-separated)" multiline rows={3} required invalid={!!errors.steps[index].preAggregatorColumns} invalidmessage={errors.steps[index].preAggregatorColumns} /> </div> </div> ))} </div> ); case 'join': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Join Columns</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4 style={{ color: '#35B0CB' }}>STEP {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Join Columns" name="joinColumns" value={step.joinColumns} input={(e) => handleInputChange(e, index)} placeholder="Enter columns (comma-separated)" multiline rows={3} required invalid={!!errors.steps[index].joinColumns} invalidmessage={errors.steps[index].joinColumns} /> </div> </div> ))} </div> ); case 'allocation': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Allocation Columns</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4 style={{ color: '#35B0CB' }}>STEP {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Allocation Columns" name="allocationColumns" value={step.allocationColumns} input={(e) => handleInputChange(e, index)} placeholder="Enter columns (comma-separated)" multiline rows={3} required invalid={!!errors.steps[index].allocationColumns} invalidmessage={errors.steps[index].allocationColumns} /> </div> </div> ))} </div> ); case 'driver': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Driver Information</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4 style={{ color: '#35B0CB' }}>STEP {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Driver Table ID" name="driverTableID" value={step.driverTableID} input={(e) => handleInputChange(e, index)} placeholder="Enter driver table ID" required invalid={!!errors.steps[index].driverTableID} invalidmessage={errors.steps[index].driverTableID} /> </div> <div className={styles.inputGroup}> <McInput label="Driver Weight Column" name="driverWeightColumn" value={step.driverWeightColumn} input={(e) => handleInputChange(e, index)} placeholder="Enter driver weight column" required invalid={!!errors.steps[index].driverWeightColumn} invalidmessage={errors.steps[index].driverWeightColumn} /> </div> <div className={styles.inputGroup}> <McInput label="Driver Filters" name="driverFilters" value={step.driverFilters} input={(e) => handleInputChange(e, index)} placeholder="Enter filters" multiline rows={3} required invalid={!!errors.steps[index].driverFilters} invalidmessage={errors.steps[index].driverFilters} /> </div> </div> ))} </div> ); default: return <div className={styles.tabContent}>No Tab Selected</div>; } }; return ( <div className={styles.pageWrapper}> <div className={styles.container}> <div className={styles.card}> <div className={styles.buttonContainer}> <McButton label="Back" appearance="neutral" click={handleCancel} className={styles.actionButton} /> <McButton label="Save" appearance="primary" click={handleSave} className={styles.actionButton} loading={isLoading} disabled={isLoading} /> </div> <div className={styles.tabs}> <button className={`${styles.tabButton} ${activeTab === 'ruleInfo' ? styles.activeTab : ''}`} onClick={() => setActiveTab('ruleInfo')} > Rule Info </button> <button className={`${styles.tabButton} ${activeTab === 'step' ? styles.activeTab : ''}`} onClick={() => setActiveTab('step')} > Step </button> <button className={`${styles.tabButton} ${activeTab === 'source' ? styles.activeTab : ''}`} onClick={() => setActiveTab('source')} > Source </button> <button className={`${styles.tabButton} ${activeTab === 'preAggregate' ? styles.activeTab : ''}`} onClick={() => setActiveTab('preAggregate')} > Pre-Aggregate </button> <button className={`${styles.tabButton} ${activeTab === 'join' ? styles.activeTab : ''}`} onClick={() => setActiveTab('join')} > Join </button> <button className={`${styles.tabButton} ${activeTab === 'allocation' ? styles.activeTab : ''}`} onClick={() => setActiveTab('allocation')} > Allocation </button> <button className={`${styles.tabButton} ${activeTab === 'driver' ? styles.activeTab : ''}`} onClick={() => setActiveTab('driver')} > Driver </button> </div> {renderTabContent()} </div> </div> </div> ); }; export default CreateRules; import React, { useState, useCallback, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { McButton, McInput, McMultiSelect, McSelect } from '@maersk-global/mds-react-wrapper'; import { McOption } from '@maersk-global/mds-react-wrapper/components-core/mc-option'; import styles from '../styles/CreateRule.module.css'; import data from '../data/PnLGroup.json'; class ErrorBoundary extends React.Component { state = { hasError: false }; static getDerivedStateFromError() { return { hasError: true }; } render() { if (this.state.hasError) { return <div>Something went wrong. Please refresh the page.</div>; } return this.props.children; } } const CreateRules = () => { const navigate = useNavigate(); const [activeTab, setActiveTab] = useState('ruleInfo'); const [isLoading, setIsLoading] = useState(false); const [ruleData, setRuleData] = useState({ num: '', name: '', desc: '', custRefID: '', ruleGroup: '', isActive: 'Y', pnlGroup: '', }); const [steps, setSteps] = useState([ { stepNo: '', stepName: 'Single Step', stepDesc: '', stepType: 'S', preAggregatorColumns: [], sourceTableID: '', sourceFilters: [], sourceOperator: '', joinColumns: [], allocationColumns: [], driverTableID: '', driverWeightColumn: '', driverFilters: [], driverOperator: '', }, ]); const [errors, setErrors] = useState({ rule: {}, steps: [{}] }); const pnLGroups = data.PnLGroups && typeof data.PnLGroups === 'object' ? Object.keys(data.PnLGroups) : []; const ruleGroups = ruleData.pnlGroup && data.PnLGroups[ruleData.pnlGroup] ? data.PnLGroups[ruleData.pnlGroup].RuleGroups || [] : []; const sourceFilterOptions = [ { value: 'Source_Filter_1', label: 'Source Filter 1' }, { value: 'Source_Filter_2', label: 'Source Filter 2' }, { value: 'Source_Filter_3', label: 'Source Filter 3' }, ]; const preAggregatorOptions = [ { value: 'column1', label: 'Column 1' }, { value: 'column2', label: 'Column 2' }, { value: 'column3', label: 'Column 3' }, ]; const joinColumnsOptions = [ { value: 'join_col1', label: 'Join Column 1' }, { value: 'join_col2', label: 'Join Column 2' }, { value: 'join_col3', label: 'Join Column 3' }, ]; const allocationColumnsOptions = [ { value: 'alloc_col1', label: 'Allocation Column 1' }, { value: 'alloc_col2', label: 'Allocation Column 2' }, { value: 'alloc_col3', label: 'Allocation Column 3' }, ]; const driverFilterOptions = [ { value: 'Driver_Type_1', label: 'Driver Type: Type 1' }, { value: 'Driver_Type_2', label: 'Driver Type: Type 2' }, { value: 'Driver_Status_Active', label: 'Driver Status: Active' }, ]; const operatorOptions = useMemo(() => [ { value: 'IN', label: 'IN' }, { value: 'NOT IN', label: 'NOT IN' }, { value: 'EQ', label: 'EQ' }, { value: 'NTEQ', label: 'NTEQ' }, { value: 'IS NULL', label: 'IS NULL' }, { value: 'GT', label: 'GT' }, { value: 'LT', label: 'LT' }, { value: 'GTEQ', label: 'GTEQ' }, { value: 'LTEQ', label: 'LTEQ' }, { value: 'BETWEEN', label: 'BETWEEN' }, { value: 'NOT BETWEEN', label: 'NOT BETWEEN' }, { value: 'LIKE', label: 'LIKE' }, ], []); const addStep = useCallback(() => { setSteps((prevSteps) => [ ...prevSteps, { stepNo: '', stepName: 'Single Step', stepDesc: '', stepType: 'S', preAggregatorColumns: [], sourceTableID: '', sourceFilters: [], sourceOperator: '', joinColumns: [], allocationColumns: [], driverTableID: '', driverWeightColumn: '', driverFilters: [], driverOperator: '', }, ]); setErrors((prevErrors) => ({ ...prevErrors, steps: [...prevErrors.steps, {}], })); }, []); const removeStep = useCallback((index) => { if (steps.length === 1) { alert('At least one step is required.'); return; } setSteps((prevSteps) => prevSteps.filter((_, i) => i !== index)); setErrors((prevErrors) => ({ ...prevErrors, steps: prevErrors.steps.filter((_, i) => i !== index), })); }, [steps.length]); const validateForm = useCallback(() => { try { const newErrors = { rule: {}, steps: steps.map(() => ({})) }; let isValid = true; if (!ruleData.num) { newErrors.rule.num = 'Rule Number is required'; isValid = false; } else if (!/^[a-zA-Z0-9]+$/.test(ruleData.num)) { newErrors.rule.num = 'Rule Number must be alphanumeric'; isValid = false; } if (!ruleData.name) { newErrors.rule.name = 'Rule Name is required'; isValid = false; } if (!ruleData.desc) { newErrors.rule.desc = 'Description is required'; isValid = false; } if (!ruleData.custRefID) { newErrors.rule.custRefID = 'Customer Reference ID is required'; isValid = false; } if (!ruleData.pnlGroup) { newErrors.rule.pnlGroup = 'PnL Group is required'; isValid = false; } if (!ruleData.ruleGroup) { newErrors.rule.ruleGroup = 'Rule Group is required'; isValid = false; } if (!ruleData.isActive) { newErrors.rule.isActive = 'Active status is required'; isValid = false; } const stepNumbers = new Set(); steps.forEach((step, index) => { const stepErrors = {}; if (!step.stepNo) { stepErrors.stepNo = 'Step Number is required'; isValid = false; } else if (stepNumbers.has(step.stepNo)) { stepErrors.stepNo = 'Step Number must be unique'; isValid = false; } else { stepNumbers.add(step.stepNo); } if (!step.stepName) { stepErrors.stepName = 'Step Name is required'; isValid = false; } if (!step.stepDesc) { stepErrors.stepDesc = 'Step Description is required'; isValid = false; } if (!step.stepType) { stepErrors.stepType = 'Step Type is required'; isValid = false; } if (!step.preAggregatorColumns.length) { stepErrors.preAggregatorColumns = 'Pre-Aggregator Columns are required'; isValid = false; } if (!step.sourceTableID) { stepErrors.sourceTableID = 'Source Table ID is required'; isValid = false; } if (!step.sourceFilters.length) { stepErrors.sourceFilters = 'Source Filters are required'; isValid = false; } if (!step.sourceOperator) { stepErrors.sourceOperator = 'Source Operator is required'; isValid = false; } if (!step.joinColumns.length) { stepErrors.joinColumns = 'Join Columns are required'; isValid = false; } if (!step.allocationColumns.length) { stepErrors.allocationColumns = 'Allocation Columns are required'; isValid = false; } if (!step.driverTableID) { stepErrors.driverTableID = 'Driver Table ID is required'; isValid = false; } if (!step.driverWeightColumn) { stepErrors.driverWeightColumn = 'Driver Weight Column is required'; isValid = false; } if (!step.driverFilters.length) { stepErrors.driverFilters = 'Driver Filters are required'; isValid = false; } if (!step.driverOperator) { stepErrors.driverOperator = 'Driver Operator is required'; isValid = false; } newErrors.steps[index] = stepErrors; }); setErrors(newErrors); return isValid; } catch (error) { alert('An error occurred during form validation. Please try again.'); return false; } }, [ruleData, steps]); const parseColumns = (input) => input; const parseFilters = (filters, operator) => { if (!filters.length || !operator) return []; return filters.map((filter) => ({ name: filter, filterType: operator, values: filter, })); }; const handleInputChange = useCallback((e, stepIndex = null) => { const { name, value } = e.target; if (stepIndex !== null) { setSteps((prevSteps) => { const newSteps = [...prevSteps]; newSteps[stepIndex] = { ...newSteps[stepIndex], [name]: value }; return newSteps; }); setErrors((prevErrors) => ({ ...prevErrors, steps: prevErrors.steps.map((stepErrors, i) => i === stepIndex ? { ...stepErrors, [name]: '' } : stepErrors ), })); } else { setRuleData((prevData) => ({ ...prevData, [name]: value, ...(name === 'pnlGroup' ? { ruleGroup: '' } : {}), })); setErrors((prevErrors) => ({ ...prevErrors, rule: { ...prevErrors.rule, [name]: '' }, })); } }, []); const handleMultiSelectChange = useCallback((e, stepIndex, fieldName) => { const selectedValues = e.detail.map((option) => option.value); setSteps((prevSteps) => { const newSteps = [...prevSteps]; newSteps[stepIndex] = { ...newSteps[stepIndex], [fieldName]: selectedValues }; return newSteps; }); setErrors((prevErrors) => ({ ...prevErrors, steps: prevErrors.steps.map((stepErrors, i) => i === stepIndex ? { ...stepErrors, [fieldName]: '' } : stepErrors ), })); }, []); const resetForm = useCallback(() => { setRuleData({ num: '', name: '', desc: '', custRefID: '', ruleGroup: '', isActive: 'Y', pnlGroup: '', }); setSteps([ { stepNo: '', stepName: 'Single Step', stepDesc: '', stepType: 'S', preAggregatorColumns: [], sourceTableID: '', sourceFilters: [], sourceOperator: '', joinColumns: [], allocationColumns: [], driverTableID: '', driverWeightColumn: '', driverFilters: [], driverOperator: '', }, ]); setErrors({ rule: {}, steps: [{}] }); setActiveTab('ruleInfo'); }, []); const handleSave = useCallback(async () => { if (!validateForm()) { alert('Please fill out all required fields.'); return; } setIsLoading(true); const ruleJson = { rules: { rule: [ { num: ruleData.num, name: ruleData.name, desc: ruleData.desc, custRefID: ruleData.custRefID, ruleGroup: ruleData.ruleGroup, isActive: ruleData.isActive, Step: steps.map((step, index) => ({ stepNo: step.stepNo || `${ruleData.num}.${index + 1}`, stepName: step.stepName === 'Single Step' ? 'single' : 'multi', stepDesc: step.stepDesc, stepType: step.stepType, isActive: 'Y', SourceTable: { id: step.sourceTableID, Name: step.sourceTableID, }, sourceFilters: { columns: parseFilters(step.sourceFilters, step.sourceOperator), operator: step.sourceOperator, }, preAggregator: { columns: parseColumns(step.preAggregatorColumns), }, join: { columns: parseColumns(step.joinColumns), }, allocation: { columns: parseColumns(step.allocationColumns), }, driver: { driverTableID: step.driverTableID, driverWeightColumn: step.driverWeightColumn, driverFilters: { columns: parseFilters(step.driverFilters, step.driverOperator), operator: step.driverOperator, }, }, })), }, ], }, }; const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 10000); try { const response = await fetch('/api/rules', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: JSON.stringify(ruleJson), signal: controller.signal, }); clearTimeout(timeoutId); if (response.ok) { alert('Rule created successfully!'); resetForm(); navigate('/'); } else { const errorData = await response.json().catch(() => ({ message: response.statusText })); alert(`Failed to create rule: ${errorData.message || response.statusText}`); } } catch (error) { if (error.name === 'AbortError') { alert('Request timed out. Please try again.'); } else { alert('An error occurred while saving the rule. Please try again.'); } } finally { setIsLoading(false); } }, [validateForm, ruleData, steps, resetForm, navigate]); const handleCancel = useCallback(() => { navigate('/'); }, [navigate]); const renderTabContent = () => { switch (activeTab) { case 'ruleInfo': return ( <div className={styles.tabContent}> {Object.values(errors.rule).some((error) => error) && ( <div className={styles.errorSummary}> <h4>Please fix the following errors:</h4> <ul> {Object.entries(errors.rule).map(([key, error]) => error && ( <li key={key}>{error}</li> ))} </ul> </div> )} <h3 className={styles.sectionTitle}>Rule Information</h3> <div className={styles.formGrid}> <div className={styles.gridItem}> <McSelect label="PnL Group" name="pnlGroup" value={ruleData.pnlGroup} input={handleInputChange} placeholder="Select a PnL Group" required invalid={!!errors.rule.pnlGroup} invalidmessage={errors.rule.pnlGroup} > {pnLGroups.map((group) => ( <McOption key={group} value={group}> {group} </McOption> ))} </McSelect> </div> <div className={styles.gridItem}> <McSelect label="Rule Group" name="ruleGroup" value={ruleData.ruleGroup} input={handleInputChange} placeholder={ruleGroups.length ? "Select a Rule Group" : "Select a PnL Group first"} required disabled={!ruleData.pnlGroup || !ruleGroups.length} invalid={!!errors.rule.ruleGroup} invalidmessage={errors.rule.ruleGroup} > {ruleGroups.map((group) => ( <McOption key={group} value={group}> {group} </McOption> ))} </McSelect> </div> </div> <div className={styles.inputGroup}> <McInput label="Rule Number" name="num" value={ruleData.num} input={handleInputChange} placeholder="Enter rule number" required invalid={!!errors.rule.num} invalidmessage={errors.rule.num} /> </div> <div className={styles.inputGroup}> <McInput label="Rule Name" name="name" value={ruleData.name} input={handleInputChange} placeholder="Enter rule name" required invalid={!!errors.rule.name} invalidmessage={errors.rule.name} /> </div> <div className={styles.inputGroup}> <McInput label="Description" name="desc" value={ruleData.desc} input={handleInputChange} placeholder="Enter rule description" multiline rows={3} required invalid={!!errors.rule.desc} invalidmessage={errors.rule.desc} /> </div> <div className={styles.inputGroup}> <McInput label="Customer Reference ID" name="custRefID" value={ruleData.custRefID} input={handleInputChange} placeholder="Enter customer reference ID" required invalid={!!errors.rule.custRefID} invalidmessage={errors.rule.custRefID} /> </div> </div> ); case 'step': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Step Information</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4 style={{ color: '#35B0CB' }}>STEP {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Step Number" name="stepNo" value={step.stepNo} input={(e) => handleInputChange(e, index)} placeholder={`Enter step number (e.g., ${ruleData.num}.${index + 1})`} required invalid={!!errors.steps[index].stepNo} invalidmessage={errors.steps[index].stepNo} /> </div> <div className={styles.inputGroup}> <McSelect label="Step Name" name="stepName" value={step.stepName} input={(e) => handleInputChange(e, index)} required placeholder="Select Step Name" invalid={!!errors.steps[index].stepName} invalidmessage={errors.steps[index].stepName} > <McOption value="Single Step">Single Step</McOption> <McOption value="Multi Step">Multi Step</McOption> </McSelect> </div> <div className={styles.inputGroup}> <McInput label="Step Description" name="stepDesc" value={step.stepDesc} input={(e) => handleInputChange(e, index)} placeholder="Enter step description" multiline rows={3} required invalid={!!errors.steps[index].stepDesc} invalidmessage={errors.steps[index].stepDesc} /> </div> <div className={styles.inputGroup}> <McSelect label="Step Type" name="stepType" value={step.stepType} input={(e) => handleInputChange(e, index)} required placeholder="Select Step Type" invalid={!!errors.steps[index].stepType} invalidmessage={errors.steps[index].stepType} > <McOption value="S">S</McOption> <McOption value="M">M</McOption> </McSelect> </div> </div> ))} <div className={styles.stepButtonContainer}> <McButton label="Add Step" appearance="secondary" click={addStep} className={styles.actionButton} /> {steps.length > 1 && ( <McButton label="Remove Step" appearance="neutral" click={() => removeStep(steps.length - 1)} className={styles.actionButton} /> )} </div> </div> ); case 'source': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Source Information</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4 style={{ color: '#35B0CB' }}>STEP {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Source Table ID" name="sourceTableID" value={step.sourceTableID} input={(e) => handleInputChange(e, index)} placeholder="Enter source table ID" required invalid={!!errors.steps[index].sourceTableID} invalidmessage={errors.steps[index].sourceTableID} /> </div> <div className={styles.inputGroup}> <McMultiSelect label="Source Filters" name="sourceFilters" value={step.sourceFilters} optionselected={(e) => handleMultiSelectChange(e, index, 'sourceFilters')} placeholder="Select source filters" required invalid={!!errors.steps[index].sourceFilters} invalidmessage={errors.steps[index].sourceFilters} > {sourceFilterOptions.map((option) => ( <McOption key={option.value} value={option.value}> {option.label} </McOption> ))} </McMultiSelect> </div> <div className={styles.inputGroup}> <McSelect label="Source Operator" name="sourceOperator" value={step.sourceOperator} input={(e) => handleInputChange(e, index)} placeholder="Select an operator" required invalid={!!errors.steps[index].sourceOperator} invalidmessage={errors.steps[index].sourceOperator} > {operatorOptions.map((option) => ( <McOption key={option.value} value={option.value}> {option.label} </McOption> ))} </McSelect> </div> </div> ))} </div> ); case 'preAggregate': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Pre-Aggregate Columns</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4 style={{ color: '#35B0CB' }}>STEP {index + 1}</h4> <div className={styles.inputGroup}> <McMultiSelect label="Pre-Aggregator Columns" name="preAggregatorColumns" value={step.preAggregatorColumns} optionselected={(e) => handleMultiSelectChange(e, index, 'preAggregatorColumns')} placeholder="Select pre-aggregator columns" required invalid={!!errors.steps[index].preAggregatorColumns} invalidmessage={errors.steps[index].preAggregatorColumns} > {preAggregatorOptions.map((option) => ( <McOption key={option.value} value={option.value}> {option.label} </McOption> ))} </McMultiSelect> </div> </div> ))} </div> ); case 'join': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Join Columns</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4 style={{ color: '#35B0CB' }}>STEP {index + 1}</h4> <div className={styles.inputGroup}> <McMultiSelect label="Join Columns" name="joinColumns" value={step.joinColumns} optionselected={(e) => handleMultiSelectChange(e, index, 'joinColumns')} placeholder="Select join columns" required invalid={!!errors.steps[index].joinColumns} invalidmessage={errors.steps[index].joinColumns} > {joinColumnsOptions.map((option) => ( <McOption key={option.value} value={option.value}> {option.label} </McOption> ))} </McMultiSelect> </div> </div> ))} </div> ); case 'allocation': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Allocation Columns</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4 style={{ color: '#35B0CB' }}>STEP {index + 1}</h4> <div className={styles.inputGroup}> <McMultiSelect label="Allocation Columns" name="allocationColumns" value={step.allocationColumns} optionselected={(e) => handleMultiSelectChange(e, index, 'allocationColumns')} placeholder="Select allocation columns" required invalid={!!errors.steps[index].allocationColumns} invalidmessage={errors.steps[index].allocationColumns} > {allocationColumnsOptions.map((option) => ( <McOption key={option.value} value={option.value}> {option.label} </McOption> ))} </McMultiSelect> </div> </div> ))} </div> ); case 'driver': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Driver Information</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4 style={{ color: '#35B0CB' }}>STEP {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Driver Table ID" name="driverTableID" value={step.driverTableID} input={(e) => handleInputChange(e, index)} placeholder="Enter driver table ID" required invalid={!!errors.steps[index].driverTableID} invalidmessage={errors.steps[index].driverTableID} /> </div> <div className={styles.inputGroup}> <McInput label="Driver Weight Column" name="driverWeightColumn" value={step.driverWeightColumn} input={(e) => handleInputChange(e, index)} placeholder="Enter driver weight column" required invalid={!!errors.steps[index].driverWeightColumn} invalidmessage={errors.steps[index].driverWeightColumn} /> </div> <div className={styles.inputGroup}> <McMultiSelect label="Driver Filters" name="driverFilters" value={step.driverFilters} optionselected={(e) => handleMultiSelectChange(e, index, 'driverFilters')} placeholder="Select driver filters" required invalid={!!errors.steps[index].driverFilters} invalidmessage={errors.steps[index].driverFilters} > {driverFilterOptions.map((option) => ( <McOption key={option.value} value={option.value}> {option.label} </McOption> ))} </McMultiSelect> </div> <div className={styles.inputGroup}> <McSelect label="Driver Operator" name="driverOperator" value={step.driverOperator} input={(e) => handleInputChange(e, index)} placeholder="Select an operator" required invalid={!!errors.steps[index].driverOperator} invalidmessage={errors.steps[index].driverOperator} > {operatorOptions.map((option) => ( <McOption key={option.value} value={option.value}> {option.label} </McOption> ))} </McSelect> </div> </div> ))} </div> ); default: return <div className={styles.tabContent}>No Tab Selected</div>; } }; return ( <ErrorBoundary> <div className={styles.pageWrapper}> {isLoading && ( <div className={styles.loader}>Loading...</div> )} <div className={styles.container}> <div className={styles.card}> <div className={styles.buttonContainer}> <McButton label="Back" appearance="neutral" click={handleCancel} className={styles.actionButton} /> <McButton label="Save" appearance="primary" click={handleSave} className={styles.actionButton} loading={isLoading} disabled={isLoading} /> </div> <div className={styles.tabs}> <button className={`${styles.tabButton} ${activeTab === 'ruleInfo' ? styles.activeTab : ''}`} onClick={() => setActiveTab('ruleInfo')} > Rule Info </button> <button className={`${styles.tabButton} ${activeTab === 'step' ? styles.activeTab : ''}`} onClick={() => setActiveTab('step')} > Step </button> <button className={`${styles.tabButton} ${activeTab === 'source' ? styles.activeTab : ''}`} onClick={() => setActiveTab('source')} > Source </button> <button className={`${styles.tabButton} ${activeTab === 'preAggregate' ? styles.activeTab : ''}`} onClick={() => setActiveTab('preAggregate')} > Pre-Aggregate </button> <button className={`${styles.tabButton} ${activeTab === 'join' ? styles.activeTab : ''}`} onClick={() => setActiveTab('join')} > Join </button> <button className={`${styles.tabButton} ${activeTab === 'allocation' ? styles.activeTab : ''}`} onClick={() => setActiveTab('allocation')} > Allocation </button> <button className={`${styles.tabButton} ${activeTab === 'driver' ? styles.activeTab : ''}`} onClick={() => setActiveTab('driver')} > Driver </button> </div> {renderTabContent()} </div> </div> </div> </ErrorBoundary> ); }; export default CreateRules;
-- RECHCECKING -- ICA_Bank_Decline_Threshold_Block DROP TABLE team_kingkong.offus_ICA_Bank_Decline_Threshold_Block_breaches; -- CREATE TABLE team_kingkong.offus_ICA_Bank_Decline_Threshold_Block_breaches AS INSERT INTO team_kingkong.offus_ICA_Bank_Decline_Threshold_Block_breaches with offus_txn as (SELECT globalcardindex, transactionid, txn_amount, txn_date, paytmmerchantid, txn_timestamp, paymethod , case when edc_mid is not null then 'EDC' else 'QR' end as mid_type , isindian, txn_status FROM (SELECT DISTINCT pg_mid from cdo.total_offline_merchant_base_snapshot_v3) f INNER join (select distinct transactionid , cast(eventamount as double)/100 as txn_amount , paytmmerchantid , globalcardindex , DATE(dl_last_updated) AS txn_date , CAST(velocitytimestamp AS DOUBLE) AS txn_timestamp , paymethod , isindian from cdp_risk_transform.maquette_flattened_offus_snapshot_v3 where dl_last_updated BETWEEN DATE(DATE'2025-05-01' - INTERVAL '1' DAY) AND DATE'2025-05-31' and paymethod in ('CREDIT_CARD','DEBIT_CARD') AND actionrecommended <> 'BLOCK' AND responsestatus = 'SUCCESS') a on a.paytmmerchantid = f.pg_mid LEFT JOIN (SELECT DISTINCT mid AS edc_mid FROM paytmpgdb.entity_edc_info_snapshot_v3 WHERE terminal_status = 'ACTIVE' AND dl_last_updated >= DATE '2010-01-01') b ON a.paytmmerchantid = b.edc_mid INNER JOIN (select distinct txn_id as pg_txn_id, txn_status from dwh.pg_olap where ingest_date BETWEEN DATE'2025-05-01' AND DATE(DATE'2025-05-31' + INTERVAL '1' DAY) and txn_started_at BETWEEN DATE'2025-05-01' AND DATE(DATE'2025-05-31' + INTERVAL '1' DAY)) d on a.transactionid = d.pg_txn_id) SELECT * FROM (SELECT a.globalcardindex, A.transactionid, A.txn_amount, A.txn_date, A.paytmmerchantid, A.txn_timestamp , A.mid_type, A.paymethod , COUNT(IF((A.txn_timestamp - B.txn_timestamp) BETWEEN 0 AND 3600000, B.transactionid, NULL)) AS txn1_hr , 3 txn1_hr_threshold , COUNT(IF((A.txn_timestamp - B.txn_timestamp) BETWEEN 0 AND 21600000, B.transactionid, NULL)) AS txn6_hr , 3 txn6_hr_threshold , COUNT(IF((A.txn_timestamp - B.txn_timestamp) BETWEEN 0 AND 122400000, B.transactionid, NULL)) AS txn24_hr , 5 AS txn24_hr_threshold , 'ICA_Bank_Decline_Threshold_Block' AS rule_name FROM (SELECT * FROM offus_txn WHERE txn_date BETWEEN DATE'2025-05-01' AND DATE'2025-05-31' AND isindian = 'false')A INNER JOIN (SELECT * FROM offus_txn WHERE txn_status = 'CLOSED')B ON A.globalcardindex = b.globalcardindex AND A.paytmmerchantid = B.paytmmerchantid AND A.transactionid <> B.transactionid AND A.txn_timestamp > B.txn_timestamp GROUP BY 1,2,3,4,5,6,7,8) WHERE (txn1_hr >= txn1_hr_threshold) OR (txn6_hr >= txn6_hr_threshold AND txn_amount > 10000) OR (txn24_hr >= txn24_hr_threshold) ;
-- ICA_PerCard_PerMID_TXN_Limit -- DROP TABLE team_kingkong.offus_ICA_PerCard_PerMID_TXN_Limit_breaches; CREATE TABLE team_kingkong.offus_ICA_PerCard_PerMID_TXN_Limit_breaches AS -- INSERT INTO team_kingkong.offus_ICA_PerCard_PerMID_TXN_Limit_breaches with offus_txn as (SELECT globalcardindex, transactionid, txn_amount, txn_date, paytmmerchantid, txn_timestamp, paymethod , case when edc_mid is not null then 'EDC' else 'QR' end as mid_type , mcc, isindian, isedcrequest , CASE WHEN mcc IN (5411, 5812, 9399, 8211, 7999, 7011, 5813, 4511, 8071, 8062) THEN 1 ELSE 0 END AS non_risky_high_mcc , CASE WHEN mcc IN (5962, 7273, 7995, 5122, 6051, 6012, 5993, 5968, 5966, 5912, 6211, 5816, 4816, 5967) THEN 1 ELSE 0 END AS risky_mcc FROM (SELECT DISTINCT pg_mid from cdo.total_offline_merchant_base_snapshot_v3) f INNER join (select distinct transactionid , cast(eventamount as double)/100 as txn_amount , paytmmerchantid , globalcardindex , DATE(dl_last_updated) AS txn_date , CAST(velocitytimestamp AS DOUBLE) AS txn_timestamp , paymethod , isindian , isedcrequest from cdp_risk_transform.maquette_flattened_offus_snapshot_v3 where dl_last_updated BETWEEN DATE(DATE'2025-01-01' - INTERVAL '30' DAY) AND DATE'2025-01-31' -- BETWEEN date'2025-01-31' AND and paymethod in ('CREDIT_CARD','DEBIT_CARD') AND actionrecommended <> 'BLOCK' AND responsestatus = 'SUCCESS') a on a.paytmmerchantid = f.pg_mid LEFT JOIN (SELECT DISTINCT mid AS edc_mid FROM paytmpgdb.entity_edc_info_snapshot_v3 WHERE terminal_status = 'ACTIVE' AND dl_last_updated >= DATE '2010-01-01') b ON a.paytmmerchantid = b.edc_mid INNER JOIN (select distinct txn_id as pg_txn_id, mcc from dwh.pg_olap where ingest_date BETWEEN DATE'2025-01-01' AND DATE(DATE'2025-01-31' + INTERVAL '1' DAY) and txn_started_at BETWEEN DATE'2025-01-01' AND DATE(DATE'2025-01-31' + INTERVAL '1' DAY) and txn_status = 'SUCCESS') d on a.transactionid = d.pg_txn_id) SELECT * FROM (SELECT a.globalcardindex, A.transactionid, A.txn_amount, A.txn_date, A.paytmmerchantid, A.txn_timestamp , A.mid_type, A.paymethod, A.mcc, A.non_risky_high_mcc, A.risky_mcc , COUNT(IF((A.txn_timestamp - B.txn_timestamp) BETWEEN 0 AND 60000, B.transactionid, NULL)) AS txn1_min , CASE WHEN A.risky_mcc > 0 THEN 1 WHEN A.non_risky_high_mcc > 0 THEN 1 WHEN A.risky_mcc = 0 AND A.non_risky_high_mcc = 0 THEN 1 END AS txn1_min_threshold , COUNT(IF((A.txn_timestamp - B.txn_timestamp) BETWEEN 0 AND 86400000, B.transactionid, NULL)) AS txn1_day , CASE WHEN A.risky_mcc > 0 THEN 3 WHEN A.non_risky_high_mcc > 0 THEN 5 WHEN A.risky_mcc = 0 AND A.non_risky_high_mcc = 0 THEN 3 END AS txn1_day_threshold , COUNT(IF((A.txn_timestamp - B.txn_timestamp) BETWEEN 0 AND 604800000, B.transactionid, NULL)) AS txn7_day , CASE WHEN A.risky_mcc > 0 THEN 5 WHEN A.non_risky_high_mcc > 0 THEN 10 WHEN A.risky_mcc = 0 AND A.non_risky_high_mcc = 0 THEN 5 END AS txn7_day_threshold , COUNT(IF((A.txn_timestamp - B.txn_timestamp) BETWEEN 0 AND 2592000000, B.transactionid, NULL)) AS txn30_day , CASE WHEN A.risky_mcc > 0 THEN 15 WHEN A.non_risky_high_mcc > 0 THEN 25 WHEN A.risky_mcc = 0 AND A.non_risky_high_mcc = 0 THEN 15 END AS txn30_day_threshold , 'ICA_PerCard_PerMID_TXN_Limit' AS rule_name FROM (SELECT * FROM offus_txn WHERE txn_date BETWEEN DATE'2025-01-01' AND DATE'2025-01-31' AND isindian = 'false' AND isedcrequest = 'true')A INNER JOIN (SELECT * FROM offus_txn)B ON A.globalcardindex = b.globalcardindex AND A.paytmmerchantid = B.paytmmerchantid AND A.transactionid <> B.transactionid AND A.txn_timestamp > B.txn_timestamp GROUP BY 1,2,3,4,5,6,7,8,9,10,11) WHERE (txn1_min >= txn1_min_threshold) OR (txn1_day >= txn1_day_threshold) OR (txn7_day >= txn7_day_threshold) OR (txn30_day >= txn30_day_threshold)
-- ICA_OddTime_PerCard_PerMID_EDC CREATE TABLE team_kingkong.offus_ICA_OddTime_PerCard_PerMID_EDC_breaches AS -- INSERT INTO team_kingkong.offus_ICA_OddTime_PerCard_PerMID_EDC_breaches with offus_txn as (SELECT transactionid, txn_amount, txn_date, paytmmerchantid, txn_timestamp, globalcardindex , case when edc_mid is not null then 'EDC' else 'QR' end as mid_type , merchantcategory, merchantsubcategory, isindian FROM (SELECT DISTINCT pg_mid from cdo.total_offline_merchant_base_snapshot_v3) f INNER join (select distinct transactionid , cast(eventamount as double)/100 as txn_amount , paytmmerchantid , DATE(dl_last_updated) AS txn_date , CAST(velocitytimestamp AS DOUBLE) AS txn_timestamp , globalcardindex , merchantcategory, merchantsubcategory, isindian from cdp_risk_transform.maquette_flattened_offus_snapshot_v3 where dl_last_updated BETWEEN DATE(DATE'2025-02-01' - INTERVAL '1' DAY) AND DATE'2025-02-28' and paymethod in ('CREDIT_CARD','DEBIT_CARD') AND actionrecommended <> 'BLOCK') a on a.paytmmerchantid = f.pg_mid LEFT JOIN (SELECT DISTINCT mid AS edc_mid FROM paytmpgdb.entity_edc_info_snapshot_v3 WHERE terminal_status = 'ACTIVE' AND dl_last_updated >= DATE '2010-01-01') b ON a.paytmmerchantid = b.edc_mid) SELECT * FROM (SELECT A.transactionid, A.txn_amount, A.txn_date, A.paytmmerchantid, A.globalcardindex, A.mid_type, 'ICA_OddTime_PerCard_PerMID_EDC' AS rule_name, A.txn_timestamp , 5000 as per_txn_limit , COUNT(B.transactionid) as txn1_day , 2 as txn1_day_threshold FROM (SELECT * FROM offus_txn WHERE txn_date BETWEEN date '2025-02-01' AND DATE'2025-02-28' AND isindian = 'false' AND HOUR(FROM_UNIXTIME(txn_timestamp / 1000)) BETWEEN 0 AND 4 AND (merchantsubcategory NOT IN ('Restaurant', 'Foodcourt','Restaurants and Bars', 'Fast Food and QSR' , 'Hotel', 'Aviation','Tours and Travel Agency' , 'Pharmacy', 'Hospital','Taxi','Pharmacy', 'Hospital', 'Taxi') OR merchantcategory NOT IN ('Airport','Gas and Petrol')))A LEFT JOIN (SELECT * FROM offus_txn)B ON A.globalcardindex = B.globalcardindex AND A.paytmmerchantid = B.paytmmerchantid AND (A.txn_timestamp - B.txn_timestamp) BETWEEN 0 AND 86400000 -- <= 1day AND A.transactionid <> B.transactionid GROUP BY 1,2,3,4,5,6,7,8) WHERE (txn_amount > per_txn_limit) OR (txn1_day>= txn1_day_threshold) -- LIMIT 100 ;
-- Merchant_PerTxnLimit_Check -- CREATE TABLE team_kingkong.offus_Merchant_PerTxnLimit_Check_breaches AS INSERT INTO team_kingkong.offus_Merchant_PerTxnLimit_Check_breaches SELECT transactionid, txn_amount, txn_date, paytmmerchantid, txn_timestamp, paymethod , case when edc_mid is not null then 'EDC' else 'QR' end as mid_type , C.per_txn_limit , C.limit_date FROM (SELECT DISTINCT pg_mid from cdo.total_offline_merchant_base_snapshot_v3) f INNER join (select distinct transactionid , cast(eventamount as double)/100 as txn_amount , paytmmerchantid , globalcardindex , DATE(dl_last_updated) AS txn_date , CAST(velocitytimestamp AS DOUBLE) AS txn_timestamp , paymethod from cdp_risk_transform.maquette_flattened_offus_snapshot_v3 where dl_last_updated BETWEEN DATE(DATE'2025-05-01' - INTERVAL '1' DAY) AND DATE'2025-05-31' and paymethod in ('UPI') AND actionrecommended <> 'BLOCK' AND responsestatus = 'SUCCESS') a on a.paytmmerchantid = f.pg_mid LEFT JOIN (SELECT DISTINCT mid AS edc_mid FROM paytmpgdb.entity_edc_info_snapshot_v3 WHERE terminal_status = 'ACTIVE' AND dl_last_updated >= DATE '2010-01-01') b ON a.paytmmerchantid = b.edc_mid INNER JOIN (SELECT content as mid, CAST(comment AS DOUBLE) as per_txn_limit, "timestamp" as limit_date FROM team_kingkong.merchant_limit_list)C ON a.paytmmerchantid = C.mid AND a.txn_date > DATE(FROM_UNIXTIME(CAST(limit_date AS double) / 1000)) WHERE a.txn_amount > C.per_txn_limit;
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using TMPro; public class CombatActionUI : MonoBehaviour { [SerializeField] private GameObject visualContainer; [SerializeField] private Button[] combatActionButtons; void OnEnable () { TurnManager.Instance.OnBeginTurn += OnBeginTurn; TurnManager.Instance.OnEndTurn += OnEndTurn; } void OnDisable () { TurnManager.Instance.OnBeginTurn -= OnBeginTurn; TurnManager.Instance.OnEndTurn -= OnEndTurn; } void OnBeginTurn (Character character) { if(!character.IsPlayer) return; visualContainer.SetActive(true); for(int i = 0; i < combatActionButtons.Length; i++) { if(i < character.CombatActions.Count) { combatActionButtons[i].gameObject.SetActive(true); CombatAction ca = character.CombatActions[i]; combatActionButtons[i].GetComponentInChildren<TextMeshProUGUI>().text = ca.DisplayName; combatActionButtons[i].onClick.RemoveAllListeners(); combatActionButtons[i].onClick.AddListener(() => OnClickCombatAction(ca)); } else { combatActionButtons[i].gameObject.SetActive(false); } } } void OnEndTurn (Character character) { visualContainer.SetActive(false); } public void OnClickCombatAction (CombatAction combatAction) { TurnManager.Instance.CurrentCharacter.CastCombatAction(combatAction); } }
{ "blocks": [ { "type": "header", "text": { "type": "plain_text", "text": ":star: Xero Boost Days! :star:" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "Canberra! Please see below for what's on this week! " } }, { "type": "divider" }, { "type": "header", "text": { "type": "plain_text", "text": ":calendar-date-21: Wednesday, 21st July", "emoji": true } }, { "type": "section", "text": { "type": "mrkdwn", "text": "\n:Lunch: *Lunch*: Provided in our suite from *12pm*." } }, { "type": "divider" }, { "type": "section", "text": { "type": "mrkdwn", "text": "Stay tuned to this channel for more details, check out the <https://calendar.google.com/calendar/u/0?cid=Y19jYzU3YWJkZTE4ZTE0YzVlYTYxMGU4OThjZjRhYWQ0MTNhYmIzMDBjZjBkMzVlNDg0M2M5NDQ4NDk3NDAyYjkyQGdyb3VwLmNhbGVuZGFyLmdvb2dsZS5jb20|*Canberra Social Calendar*>, and get ready to Boost your workdays!\n\nLove,\nWX Team :party-wx:" } } ] }
{ "blocks": [ { "type": "header", "text": { "type": "plain_text", "text": ":star: Xero Boost Days! :star:" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "Canberra! Please see below for what's on this week! " } }, { "type": "divider" }, { "type": "header", "text": { "type": "plain_text", "text": ":calendar-date-14: Wednesday, 14th July", "emoji": true } }, { "type": "section", "text": { "type": "mrkdwn", "text": "\n:Lunch: *Lunch*: Provided in our suite from *12pm*." } }, { "type": "divider" }, { "type": "section", "text": { "type": "mrkdwn", "text": "Stay tuned to this channel for more details, check out the <https://calendar.google.com/calendar/u/0?cid=Y19jYzU3YWJkZTE4ZTE0YzVlYTYxMGU4OThjZjRhYWQ0MTNhYmIzMDBjZjBkMzVlNDg0M2M5NDQ4NDk3NDAyYjkyQGdyb3VwLmNhbGVuZGFyLmdvb2dsZS5jb20|*Canberra Social Calendar*>, and get ready to Boost your workdays!\n\nLove,\nWX Team :party-wx:" } } ] }
{ "blocks": [ { "type": "header", "text": { "type": "plain_text", "text": ":star: Xero Boost Days! :star:" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "Canberra! Please see below for what's on this week! " } }, { "type": "divider" }, { "type": "header", "text": { "type": "plain_text", "text": ":calendar-date-7: Wednesday, 7th July", "emoji": true } }, { "type": "section", "text": { "type": "mrkdwn", "text": "\n:Lunch: *Lunch*: Provided in our suite from *12pm*." } }, { "type": "divider" }, { "type": "section", "text": { "type": "mrkdwn", "text": "Stay tuned to this channel for more details, check out the <https://calendar.google.com/calendar/u/0?cid=Y19jYzU3YWJkZTE4ZTE0YzVlYTYxMGU4OThjZjRhYWQ0MTNhYmIzMDBjZjBkMzVlNDg0M2M5NDQ4NDk3NDAyYjkyQGdyb3VwLmNhbGVuZGFyLmdvb2dsZS5jb20|*Canberra Social Calendar*>, and get ready to Boost your workdays!\n\nLove,\nWX Team :party-wx:" } } ] }
{ "blocks": [ { "type": "header", "text": { "type": "plain_text", "text": ":star: Xero Boost Days! :star:" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "Canberra! Please see below for what's on this week! " } }, { "type": "divider" }, { "type": "header", "text": { "type": "plain_text", "text": ":calendar-date-30: Wednesday, 30th June", "emoji": true } }, { "type": "section", "text": { "type": "mrkdwn", "text": "\n:Lunch: *Lunch*: Provided in our suite from *12pm*." } }, { "type": "divider" }, { "type": "section", "text": { "type": "mrkdwn", "text": "Stay tuned to this channel for more details, check out the <https://calendar.google.com/calendar/u/0?cid=Y19jYzU3YWJkZTE4ZTE0YzVlYTYxMGU4OThjZjRhYWQ0MTNhYmIzMDBjZjBkMzVlNDg0M2M5NDQ4NDk3NDAyYjkyQGdyb3VwLmNhbGVuZGFyLmdvb2dsZS5jb20|*Canberra Social Calendar*>, and get ready to Boost your workdays!\n\nLove,\nWX Team :party-wx:" } } ] }
{ "blocks": [ { "type": "header", "text": { "type": "plain_text", "text": ":star: Xero Boost Days! :star:" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "Canberra! Please see below for what's on this week! " } }, { "type": "divider" }, { "type": "header", "text": { "type": "plain_text", "text": ":calendar-date-23: Wednesday, 23rd June", "emoji": true } }, { "type": "section", "text": { "type": "mrkdwn", "text": "\n:Lunch: *Lunch*: Provided in our suite from *12pm*." } }, { "type": "divider" }, { "type": "section", "text": { "type": "mrkdwn", "text": "Stay tuned to this channel for more details, check out the <https://calendar.google.com/calendar/u/0?cid=Y19jYzU3YWJkZTE4ZTE0YzVlYTYxMGU4OThjZjRhYWQ0MTNhYmIzMDBjZjBkMzVlNDg0M2M5NDQ4NDk3NDAyYjkyQGdyb3VwLmNhbGVuZGFyLmdvb2dsZS5jb20|*Canberra Social Calendar*>, and get ready to Boost your workdays!\n\nLove,\nWX Team :party-wx:" } } ] }
{ "blocks": [ { "type": "header", "text": { "type": "plain_text", "text": ":star: Xero Boost Days! :star:" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "Canberra! Please see below for what's on this week! " } }, { "type": "divider" }, { "type": "header", "text": { "type": "plain_text", "text": ":calendar-date-16: Wednesday, 16th June", "emoji": true } }, { "type": "section", "text": { "type": "mrkdwn", "text": "\n:Lunch: *Lunch*: Provided in our suite from *12pm*." } }, { "type": "divider" }, { "type": "section", "text": { "type": "mrkdwn", "text": "Stay tuned to this channel for more details, check out the <https://calendar.google.com/calendar/u/0?cid=Y19jYzU3YWJkZTE4ZTE0YzVlYTYxMGU4OThjZjRhYWQ0MTNhYmIzMDBjZjBkMzVlNDg0M2M5NDQ4NDk3NDAyYjkyQGdyb3VwLmNhbGVuZGFyLmdvb2dsZS5jb20|*Canberra Social Calendar*>, and get ready to Boost your workdays!\n\nLove,\nWX Team :party-wx:" } } ] }
{ "blocks": [ { "type": "header", "text": { "type": "plain_text", "text": ":star: Xero Boost Days! :star:" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "Canberra! Please see below for what's on this week! " } }, { "type": "divider" }, { "type": "header", "text": { "type": "plain_text", "text": ":calendar-date-9: Wednesday, 9th June", "emoji": true } }, { "type": "section", "text": { "type": "mrkdwn", "text": "\n:Lunch: *Lunch*: Provided in our suite from *12pm*." } }, { "type": "divider" }, { "type": "section", "text": { "type": "mrkdwn", "text": "Stay tuned to this channel for more details, check out the <https://calendar.google.com/calendar/u/0?cid=Y19jYzU3YWJkZTE4ZTE0YzVlYTYxMGU4OThjZjRhYWQ0MTNhYmIzMDBjZjBkMzVlNDg0M2M5NDQ4NDk3NDAyYjkyQGdyb3VwLmNhbGVuZGFyLmdvb2dsZS5jb20|*Canberra Social Calendar*>, and get ready to Boost your workdays!\n\nLove,\nWX Team :party-wx:" } } ] }
{ "blocks": [ { "type": "header", "text": { "type": "plain_text", "text": ":star: Xero Boost Days! :star:" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "Canberra! Please see below for what's on this week! " } }, { "type": "divider" }, { "type": "header", "text": { "type": "plain_text", "text": ":calendar-date-2: Wednesday, 2nd June", "emoji": true } }, { "type": "section", "text": { "type": "mrkdwn", "text": "\n:Lunch: *Lunch*: Provided in our suite from *12pm*." } }, { "type": "divider" }, { "type": "section", "text": { "type": "mrkdwn", "text": "Stay tuned to this channel for more details, check out the <https://calendar.google.com/calendar/u/0?cid=Y19jYzU3YWJkZTE4ZTE0YzVlYTYxMGU4OThjZjRhYWQ0MTNhYmIzMDBjZjBkMzVlNDg0M2M5NDQ4NDk3NDAyYjkyQGdyb3VwLmNhbGVuZGFyLmdvb2dsZS5jb20|*Canberra Social Calendar*>, and get ready to Boost your workdays!\n\nLove,\nWX Team :party-wx:" } } ] }
curl -fsSL https://raw.githubusercontent.com/filebrowser/get/master/get.sh | bash filebrowser -r /path/to/your/files
sudo add-apt-repository ppa:christian-boxdoerfer/fsearch-stable sudo apt update
{ "blocks": [ { "type": "header", "text": { "type": "plain_text", "text": ":aboriginal_flag: Xero Boost Days - What's On :aboriginal_flag:" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "Good Morning Warrane, and welcome to Reconciliation Week!\n\n *Reconciliation Week (27 May – 3 June)* is a time for all Australians to learn about our shared histories, cultures, and achievements, and to explore how we can contribute to reconciliation in Australia. \n\n For Aboriginal and Torres Strait Islander peoples, it’s a powerful reminder of ongoing resilience, the importance of truth-telling, and the work still needed to achieve genuine equity and justice." } }, { "type": "divider" }, { "type": "header", "text": { "type": "plain_text", "text": ":calendar-date-28: Wednesday, 28th May", "emoji": true } }, { "type": "section", "text": { "type": "mrkdwn", "text": "\n:coffee: *Café Partnership*: Enjoy free coffee and café-style beverages from our Cafe partner *Naked Duck*.\n:breakfast: *Reconciliation breakfast*: from *9am* in the kitchen.\n\n :microphone: We will also have a video of our very own *Tony Davison* talking on behalf of the #reconciliation-au ERG around Xero's Reconciliation plan and what this week means! \n\n :slack: In the thread we will also have a special background for you to use on Google Meet if you would like to participate." } }, { "type": "header", "text": { "type": "plain_text", "text": ":calendar-date-29: Thursday, 29th May", "emoji": true } }, { "type": "section", "text": { "type": "mrkdwn", "text": ":coffee: *Café Partnership*: Enjoy free coffee and café-style beverages from our Cafe partner *Naked Duck*.\n:lunch: *Lunch* provided by Naked Duck from *9pm* in the kitchen!." } }, { "type": "divider" }, { "type": "section", "text": { "type": "mrkdwn", "text": "Stay tuned to this channel for more details, check out the <https://calendar.google.com/calendar/u/0?cid=Y185aW90ZWV0cXBiMGZwMnJ0YmtrOXM2cGFiZ0Bncm91cC5jYWxlbmRhci5nb29nbGUuY29t|*Sydney Social Calendar*>, and get ready to Boost your workdays!\n\nLove,\nWX Team :party-wx:" } } ] }
7200+ users, 1,38,000+ tracks downloaded
{ "blocks": [ { "type": "header", "text": { "type": "plain_text", "text": ":national-reconciliation-week-2025-logo: Boost Days - What's On This Week :national-reconciliation-week-2025-logo:" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "\n\n Good morning Melbourne, and Welcome to Reconciliation Week. *Reconciliation Week - (27th May- 3rd June)* is a time for Australians to learn about our shared histories, cultures, and achievements, and to explore how we can contribute to the Reconciliation in Australia.\n\n \n\n For Aboriginal and Torres Strait Islander peoples, it's a powerful reminder of ongoing resilience, the importance of truth-telling, and the work still needed to achieve genuine equity and justice. " } }, { "type": "divider" }, { "type": "header", "text": { "type": "plain_text", "text": "Xero Café :coffee:", "emoji": true } }, { "type": "section", "text": { "type": "mrkdwn", "text": "\n :new-thing: *This week we are offering some delicious sweet treats from Indigeous supplier Jarrah Catering:* \n\n :biscuit: Gourmet Biscuits :lamington: Lamingtons \n\n :coffee: *Weekly Café Special:* _Honey Cinammon Latte_" } }, { "type": "header", "text": { "type": "plain_text", "text": " Wednesday, 28 May :calendar-date-28:", "emoji": true } }, { "type": "section", "text": { "type": "mrkdwn", "text": " \n\n :lunch: *Light Lunch*: Inspired by Australian native ingredients. Lunch is from *12pm* in the L3 Kitchen & Wominjeka Breakout Space. Menu is in the:thread:\n \n :national-reconciliation-week-2025-logo::microphone: *12.30pm- Wominjeka Breakout Space*: As part of National Reconciliation week, Matt Jolly and Ash will share a presentation from Xero's RAP consultant *Rhys Paddock*. Rhys will talk about the importance of Reconciliation and how we can contribute to a more inclusive and respectful culture." } }, { "type": "header", "text": { "type": "plain_text", "text": "Thursday, 29 May :calendar-date-29:", "emoji": true } }, { "type": "section", "text": { "type": "mrkdwn", "text": ":pancakes: *Breakfast*: from *8:30am-10:30am* in the Wominjeka Breakout Space. \n\n \n\n " } }, { "type": "header", "text": { "type": "plain_text", "text": "Friday, 30 May :calendar-date-30:", "emoji": true } }, { "type": "section", "text": { "type": "mrkdwn", "text": "*Social Happy Hour:* Celebrating the Hackathon results from 4pm-5.30pm. On the menu, we have the most delicious Paella from - *Simply Spanish* and a Friday FIESTA playlist that is sure to give you that *FRIDAY FEELING* :dancer::shallow_pan_of_food::spain: " } }, { "type": "divider" } ] }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>New Swiper Carousel with Circular Titles + Tabs + Progress Bar</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@9/swiper-bundle.min.css"/> <style> body { font-family: "Manrope", Sans-serif; padding: 30px; background: #00000000; } .custom-home-slider .title-bar-wrapper { width: 100%; margin: 0 auto 30px; position: relative; height: 50px; user-select: none; } .custom-home-slider .slide-titles { position: relative; height: 100%; } .custom-home-slider .slide-title-tab { position: absolute; top: 50%; transform: translateY(-50%); font-weight: 700; font-size: 45px; color: #999; cursor: pointer; opacity: 0.5; pointer-events: auto; transition: all 0.3s ease; white-space: nowrap; user-select: none; line-height: 1.2; } .custom-home-slider .slide-title-tab.left { left: 0; transform: translateY(-50%) translateX(0); opacity: 0.6; color: #666; } .custom-home-slider .slide-title-tab.center { left: 50%; transform: translate(-50%, -50%); opacity: 1; pointer-events: none; white-space: normal; /* allow line break */ text-align: center; } .custom-home-slider .slide-title-tab.right { right: 0; transform: translateY(-50%) translateX(0); opacity: 0.6; color: #666; } .custom-home-slider .slide-title-tab.hidden { opacity: 0; pointer-events: none; } /* Swiper container */ .custom-home-slider .swiper { width: 100%; height: 520px; margin: 0 auto; padding: 20px 0; box-sizing: border-box; display: flex; flex-direction: column; } .custom-home-slider .swiper-slide { display: flex; flex-direction: column; align-items: center; justify-content: flex-start; overflow: hidden; opacity: 0; pointer-events: none; transition: opacity 0.3s ease; } /* Tabs inside each slide */ .custom-home-slider .tabs { display: flex; justify-content: center; gap: 12px; margin-bottom: 12px; user-select: none; } .custom-home-slider .tab { display: flex; justify-content: center; gap: 12px; margin-bottom: 12px; color: #fff; padding: 8px 15px; margin: 5px; cursor: pointer; background: unset; border-radius: 54px; text-transform: uppercase; font-size: 18px; } .custom-home-slider .design .tab { border: 1px solid #E36F30; } .custom-home-slider .design .tab.active { background: linear-gradient(90deg, #E36F30 0%, #FBC32A 100%); } .custom-home-slider .design .tab:hover { background: linear-gradient(90deg, #E36F30 0%, #FBC32A 100%); } .custom-home-slider .inno .tab { border: 1px solid #d82afb; } .custom-home-slider .inno .tab:hover { background: linear-gradient(90deg, #30BDE5 0%, #d82afb 100%); } .custom-home-slider .inno .tab.active { background: linear-gradient(90deg, #30BDE5 0%, #d82afb 100%); } .custom-home-slider .marketing .tab { border: 1px solid #2AFBED; } .custom-home-slider .marketing .tab:hover { background: linear-gradient(90deg, #30E381 0%, #2AFBED 100%); } .custom-home-slider .marketing .tab.active { background: linear-gradient(90deg, #30E381 0%, #2AFBED 100%); } .custom-home-slider .tab-content { border-radius: 30px; padding: 14px; background: #3A3A3A; height: 420px; box-sizing: border-box; display: flex; } /* Arrows */ .custom-home-slider .swiper-button-prev, .custom-home-slider .swiper-button-next { color: #fff; top: 50%; } .custom-home-slider .swiper-slide-active { opacity: 1; pointer-events: auto; } .custom-home-slider .swiper-button-prev { left: 35%; } .custom-home-slider .swiper-button-next { right: 35%; } /* Progress bar container */ .custom-home-slider .progress-container { width: 100%; height: 5px; background: #D9D9D9; border-radius: 3px; margin: 50px auto 0; overflow: hidden; } /* Progress bar fill */ .custom-home-slider .progress-bar { height: 100%; width: 0%; background: linear-gradient(to right, #00c6ff, #9c27b0); transition: width 0.4s ease; } .custom-home-slider .two-column { display: flex; gap: 20px; align-items: center; } .custom-home-slider .left-column img { width: 90%; height: auto; object-fit: cover; } .custom-home-slider .right-column { flex: 1 1 70%; text-align: left; display: flex; flex-direction: column; } .custom-home-slider .icon { margin-top: 12px; width: 32px; height: 32px; } .custom-home-slider .left-column { flex: 1 1 20%; text-align: center; } .custom-home-slider h2.grad-title { font-weight: 800; font-size: 50px; margin: 0 0 10px 0; background: linear-gradient(90deg, #FFFFFF, #767585); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } .custom-home-slider p { margin-top:0; font-size: 16px; line-height: 1.5; color: #A9A9A9; font-weight: 300; width: 55%; } .custom-home-slider .slide-title-tab.inn-title.center { background: linear-gradient(90deg, #00c6ff, #9c27b0); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } .custom-home-slider .slide-title-tab.marketing-title.center { background: linear-gradient(90deg, #30E381, #2AFBED); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } .custom-home-slider .slide-title-tab.design-title.center { background: linear-gradient(90deg, #E36F30, #FBC32A); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } .custom-home-slider .right-column a img:hover { transform: rotate(45deg) scale(0.8); transition: transform 0.5s ease; } .custom-home-slider .right-column a img { transition: .3s ease all; } .custom-home-slider .swiper-button-prev:after, .custom-home-slider .swiper-button-next:after{ display:none; } .custom-home-slider .swiper-button-next img { width: 25px; } .custom-home-slider .swiper-button-next { border: none; z-index: 1; cursor: pointer; width: 50px; height: 50px; border-radius: 100px; background-color: #ffffff1a; } .custom-home-slider .swiper-button-prev img { width: 25px; } .custom-home-slider .swiper-button-prev { border: none; z-index: 1; cursor: pointer; width: 50px; height: 50px; border-radius: 100px; background-color: #ffffff1a; } .custom-home-slider .swiper-button-next:hover, .swiper-button-prev:hover{ background-color: #444; } .custom-home-slider .right-column a { width: fit-content; } .custom-home-slider .slide-title-tab.center:before { content: "DIGITAL"; display: block !important; } /* MEDAI QUERY */ @media screen and (max-width: 1600px) { .custom-home-slider .left-column img { width: 100%; } } @media screen and (max-width: 1440px) { .custom-home-slider p { width: 65%; } .custom-home-slider .swiper-button-next { right: 30%; } .custom-home-slider .swiper-button-prev { left: 30%; } .custom-home-slider .right-column a img { width: 50px; } .custom-home-slider .tab-content { height: 370px; } } @media screen and (max-width: 1366px) { .custom-home-slider h2.grad-title { font-size: 40px; } } @media screen and (max-width: 1280px) { .custom-home-slider .slide-title-tab { font-size: 40px; } } @media screen and (max-width: 1024px) { .custom-home-slider .slide-title-tab { font-size: 35px; } .custom-home-slider .tab { font-size: 14px; } .custom-home-slider p { width: 95%; } .custom-home-slider h2.grad-title { font-size: 35px; } .custom-home-slider .tabs {gap: 10px;} .custom-home-slider .tab { padding: 8px 5px; } .custom-home-slider .tab-content { height: 340px; margin-top: 10px; } .custom-home-slider .right-column a img { width: 40px; } } @media screen and (max-width: 820px) { .custom-home-slider .slide-title-tab { font-size: 30px; } .custom-home-slider .swiper-button-next, .custom-home-slider .swiper-button-prev { width: 40px; height: 40px; } .custom-home-slider .progress-container { margin: 30px auto 0; } .custom-home-slider .tab { font-size: 12px; padding: 8px 7px; } .custom-home-slider h2.grad-title { font-size: 30px; } } @media screen and (max-width: 768px) { .custom-home-slider .slide-title-tab { font-size: 25px; } .custom-home-slider .tab { font-size: 12px; padding: 8px 4px; } } @media screen and (max-width: 767px) { .custom-home-slider .slide-title-tab.left, .custom-home-slider .slide-title-tab.right { display: none; } .custom-home-slider .swiper-button-next { right: 0; } .custom-home-slider .swiper-button-prev { left: 0; } html, body{ padding: 0; } .custom-home-slider .two-column { display: flex; flex-direction: column; height: auto; gap: 0px; } .custom-home-slider .tab-content { height: auto; } .custom-home-slider .swiper-slide { height: auto; } .custom-home-slider .swiper.swiper-initialized.swiper-horizontal.swiper-ios.swiper-backface-hidden { height: auto; } .custom-home-slider .swiper-wrapper { height: auto; } .custom-home-slider .tabs { display: flex; flex-direction: column; gap:5px; } .custom-home-slider .tab { font-size: 14px; padding: 12px 24px; } } </style> </head> <body> <div class="custom-home-slider"> <div class="title-bar-wrapper"> <div class="swiper-button-prev"> <img src="https://dev.icreativesol.com/wp-content/uploads/2025/04/left-arrow.png"> </div> <div class="swiper-button-next"> <img src="https://dev.icreativesol.com/wp-content/uploads/2025/04/right-arrow.png"> </div> <div class="slide-titles"> <div class="slide-title-tab inn-title" data-slide="0">INNOVATION</div> <div class="slide-title-tab design-title" data-slide="1">DESIGN</div> <div class="slide-title-tab marketing-title" data-slide="2">MARKETING</div> </div> </div> <!-- Progress bar container --> <div class="progress-container"> <div class="progress-bar"></div> </div> <div class="swiper"> <div class="swiper-wrapper"> <!-- Slide 1 INNOVATION --> <div class="swiper-slide"> <div class="tabs-wrapper"> <div class="tabs inno"> <div class="tab active" data-tab="1">Mobile App</div> <div class="tab" data-tab="2">Game App</div> <div class="tab" data-tab="3">Web App</div> <div class="tab" data-tab="4">MVP Startup</div> <div class="tab" data-tab="5">AR</div> <div class="tab" data-tab="6">VR</div> <div class="tab" data-tab="7">E-Commerce</div> <div class="tab" data-tab="8">Startup</div> </div> </div> <div class="tab-content" data-content="1"> <div class="two-column"> <div class="left-column"> <img src="https://dev.icreativesol.com/wp-content/uploads/2025/04/mobile-group-1.webp" alt="Sample Image" /> </div> <div class="right-column"> <h2 class="grad-title">MOBILE APP DEVELOPMENT</h2> <p>The upsurge of the mobile game app industry is generating high revenues by capturing a large-scale market of game players. Building a game app that provides financial aid requires high-profile game app developers who help you discover unwavering strategies for game design and development that not only exist for entertainment but also generate hefty revenues for investors.</p> <a href="https://www.your-link.com" target="_blank"> <img class="anim-arrow-icon" src="https://dev.icreativesol.com/wp-content/uploads/2025/04/white-btn.svg" alt="Mobile App Development" style="max-width: 100%; height: auto; border-radius: 10px; margin-top: 10px;"> </a> </div> </div> </div> <div class="tab-content" data-content="2" style="display:none;"> <div class="two-column"> <div class="left-column"> <img src="https://dev.icreativesol.com/wp-content/uploads/2025/04/img-2.webp" alt="Sample Image" /> </div> <div class="right-column"> <h2 class="grad-title">GAME APP DEVELOPMENT</h2> <p>The upsurge of the mobile game app industry is generating high revenues by capturing a large-scale market of game players. Building a game app that provides financial aid requires high-profile game app developers who help you discover unwavering strategies for game design and development that not only exist for entertainment but also generate hefty revenues for investors.</p> <a href="https://www.your-link.com" target="_blank"> <img class="anim-arrow-icon" src="https://dev.icreativesol.com/wp-content/uploads/2025/04/white-btn.svg" alt="Mobile App Development" style="max-width: 100%; height: auto; border-radius: 10px; margin-top: 10px;"> </a> </div> </div> </div> <div class="tab-content" data-content="3" style="display:none;"> <div class="two-column"> <div class="left-column"> <img src="https://dev.icreativesol.com/wp-content/uploads/2025/04/img-3.webp" alt="Sample Image" /> </div> <div class="right-column"> <h2 class="grad-title">WEB APPLICATION</h2> <p>The upsurge of the mobile game app industry is generating high revenues by capturing a large-scale market of game players. Building a game app that provides financial aid requires high-profile game app developers who help you discover unwavering strategies for game design and development that not only exist for entertainment but also generate hefty revenues for investors.</p> <a href="https://www.your-link.com" target="_blank"> <img class="anim-arrow-icon" src="https://dev.icreativesol.com/wp-content/uploads/2025/04/white-btn.svg" alt="Mobile App Development" style="max-width: 100%; height: auto; border-radius: 10px; margin-top: 10px;"> </a> </div> </div> </div> <div class="tab-content" data-content="4" style="display:none;"> <div class="two-column"> <div class="left-column"> <img src="https://dev.icreativesol.com/wp-content/uploads/2025/04/img-4.webp" alt="Sample Image" /> </div> <div class="right-column"> <h2 class="grad-title">MVP STARTUP DEVELOPMENT</h2> <p>The upsurge of the mobile game app industry is generating high revenues by capturing a large-scale market of game players. Building a game app that provides financial aid requires high-profile game app developers who help you discover unwavering strategies for game design and development that not only exist for entertainment but also generate hefty revenues for investors.</p> <a href="https://www.your-link.com" target="_blank"> <img class="anim-arrow-icon" src="https://dev.icreativesol.com/wp-content/uploads/2025/04/white-btn.svg" alt="Mobile App Development" style="max-width: 100%; height: auto; border-radius: 10px; margin-top: 10px;"> </a> </div> </div> </div> <div class="tab-content" data-content="5" style="display:none;"> <div class="two-column"> <div class="left-column"> <img src="https://dev.icreativesol.com/wp-content/uploads/2025/04/mobile-group-1.webp" alt="Sample Image" /> </div> <div class="right-column"> <h2 class="grad-title">AR DEVELOPMENT</h2> <p>The upsurge of the mobile game app industry is generating high revenues by capturing a large-scale market of game players. Building a game app that provides financial aid requires high-profile game app developers who help you discover unwavering strategies for game design and development that not only exist for entertainment but also generate hefty revenues for investors.</p> <a href="https://www.your-link.com" target="_blank"> <img class="anim-arrow-icon" src="https://dev.icreativesol.com/wp-content/uploads/2025/04/white-btn.svg" alt="Mobile App Development" style="max-width: 100%; height: auto; border-radius: 10px; margin-top: 10px;"> </a> </div> </div> </div> <div class="tab-content" data-content="6" style="display:none;"> <div class="two-column"> <div class="left-column"> <img src="https://dev.icreativesol.com/wp-content/uploads/2025/04/img-6.webp" alt="Sample Image" /> </div> <div class="right-column"> <h2 class="grad-title">VR DEVELOPMENT</h2> <p>The upsurge of the mobile game app industry is generating high revenues by capturing a large-scale market of game players. Building a game app that provides financial aid requires high-profile game app developers who help you discover unwavering strategies for game design and development that not only exist for entertainment but also generate hefty revenues for investors.</p> <a href="https://www.your-link.com" target="_blank"> <img class="anim-arrow-icon" src="https://dev.icreativesol.com/wp-content/uploads/2025/04/white-btn.svg" alt="Mobile App Development" style="max-width: 100%; height: auto; border-radius: 10px; margin-top: 10px;"> </a> </div> </div> </div> <div class="tab-content" data-content="7" style="display:none;"> <div class="two-column"> <div class="left-column"> <img src="https://dev.icreativesol.com/wp-content/uploads/2025/04/img-7.webp" alt="Sample Image" /> </div> <div class="right-column"> <h2 class="grad-title">ECOMMERCE WEBSITE</h2> <p>The upsurge of the mobile game app industry is generating high revenues by capturing a large-scale market of game players. Building a game app that provides financial aid requires high-profile game app developers who help you discover unwavering strategies for game design and development that not only exist for entertainment but also generate hefty revenues for investors.</p> <a href="https://www.your-link.com" target="_blank"> <img class="anim-arrow-icon" src="https://dev.icreativesol.com/wp-content/uploads/2025/04/white-btn.svg" alt="Mobile App Development" style="max-width: 100%; height: auto; border-radius: 10px; margin-top: 10px;"> </a> </div> </div> </div> <div class="tab-content" data-content="8" style="display:none;"> <div class="two-column"> <div class="left-column"> <img src="https://dev.icreativesol.com/wp-content/uploads/2025/04/img-8.webp" alt="Sample Image" /> </div> <div class="right-column"> <h2 class="grad-title">STARTUP DEVELOPMENT</h2> <p>The upsurge of the mobile game app industry is generating high revenues by capturing a large-scale market of game players. Building a game app that provides financial aid requires high-profile game app developers who help you discover unwavering strategies for game design and development that not only exist for entertainment but also generate hefty revenues for investors.</p> <a href="https://www.your-link.com" target="_blank"> <img class="anim-arrow-icon" src="https://dev.icreativesol.com/wp-content/uploads/2025/04/white-btn.svg" alt="Mobile App Development" style="max-width: 100%; height: auto; border-radius: 10px; margin-top: 10px;"> </a> </div> </div> </div> </div> <!-- Slide 2 DESIGN --> <div class="swiper-slide"> <div class="tabs design"> <div class="tab active" data-tab="1">WEB DESIGN</div> <div class="tab" data-tab="2">LOGO DESIGN</div> <div class="tab" data-tab="3">2D-3D Illustration</div> <div class="tab" data-tab="4">MOTION GRAPHICS</div> </div> <div class="tab-content" data-content="1"> <div class="two-column"> <div class="left-column"> <img src="https://dev.icreativesol.com/wp-content/uploads/2025/04/mobile-group-1.webp" alt="Sample Image" /> </div> <div class="right-column"> <h2 class="grad-title">WEB DESIGN</h2> <p>The upsurge of the mobile game app industry is generating high revenues by capturing a large-scale market of game players. Building a game app that provides financial aid requires high-profile game app developers who help you discover unwavering strategies for game design and development that not only exist for entertainment but also generate hefty revenues for investors.</p> <a href="https://www.your-link.com" target="_blank"> <img class="anim-arrow-icon" src="https://dev.icreativesol.com/wp-content/uploads/2025/04/white-btn.svg" alt="Mobile App Development" style="max-width: 100%; height: auto; border-radius: 10px; margin-top: 10px;"> </a> </div> </div> </div> <div class="tab-content" data-content="2" style="display:none;"> <div class="two-column"> <div class="left-column"> <img src="https://dev.icreativesol.com/wp-content/uploads/2025/04/mobile-group-1.webp" alt="Sample Image" /> </div> <div class="right-column"> <h2 class="grad-title">LOGO DESIGN</h2> <p>The upsurge of the mobile game app industry is generating high revenues by capturing a large-scale market of game players. Building a game app that provides financial aid requires high-profile game app developers who help you discover unwavering strategies for game design and development that not only exist for entertainment but also generate hefty revenues for investors.</p> <a href="https://www.your-link.com" target="_blank"> <img class="anim-arrow-icon" src="https://dev.icreativesol.com/wp-content/uploads/2025/04/white-btn.svg" alt="Mobile App Development" style="max-width: 100%; height: auto; border-radius: 10px; margin-top: 10px;"> </a> </div> </div> </div> <div class="tab-content" data-content="3" style="display:none;"> <div class="two-column"> <div class="left-column"> <img src="https://dev.icreativesol.com/wp-content/uploads/2025/04/mobile-group-1.webp" alt="Sample Image" /> </div> <div class="right-column"> <h2 class="grad-title">2D-3D ILLUSTRATION</h2> <p>The upsurge of the mobile game app industry is generating high revenues by capturing a large-scale market of game players. Building a game app that provides financial aid requires high-profile game app developers who help you discover unwavering strategies for game design and development that not only exist for entertainment but also generate hefty revenues for investors.</p> <a href="https://www.your-link.com" target="_blank"> <img class="anim-arrow-icon" src="https://dev.icreativesol.com/wp-content/uploads/2025/04/white-btn.svg" alt="Mobile App Development" style="max-width: 100%; height: auto; border-radius: 10px; margin-top: 10px;"> </a> </div> </div> </div> <div class="tab-content" data-content="4" style="display:none;"> <div class="two-column"> <div class="left-column"> <img src="https://dev.icreativesol.com/wp-content/uploads/2025/04/mobile-group-1.webp" alt="Sample Image" /> </div> <div class="right-column"> <h2 class="grad-title">MOTION GRAPHICS</h2> <p>The upsurge of the mobile game app industry is generating high revenues by capturing a large-scale market of game players. Building a game app that provides financial aid requires high-profile game app developers who help you discover unwavering strategies for game design and development that not only exist for entertainment but also generate hefty revenues for investors.</p> <a href="https://www.your-link.com" target="_blank"> <img class="anim-arrow-icon" src="https://dev.icreativesol.com/wp-content/uploads/2025/04/white-btn.svg" alt="Mobile App Development" style="max-width: 100%; height: auto; border-radius: 10px; margin-top: 10px;"> </a> </div> </div> </div> </div> <!-- Slide 3 MARKETING --> <div class="swiper-slide"> <div class="tabs marketing"> <div class="tab active" data-tab="1">SOCIAL MEDIA</div> <div class="tab" data-tab="2">SEO</div> </div> <div class="tab-content" data-content="1"> <div class="two-column"> <div class="left-column"> <img src="https://dev.icreativesol.com/wp-content/uploads/2025/04/mobile-group-1.webp" alt="Sample Image" /> </div> <div class="right-column"> <h2 class="grad-title">SOCIAL MEDIA MARKETING</h2> <p>The upsurge of the mobile game app industry is generating high revenues by capturing a large-scale market of game players. Building a game app that provides financial aid requires high-profile game app developers who help you discover unwavering strategies for game design and development that not only exist for entertainment but also generate hefty revenues for investors.</p> <a href="https://www.your-link.com" target="_blank"> <img class="anim-arrow-icon" src="https://dev.icreativesol.com/wp-content/uploads/2025/04/white-btn.svg" alt="Mobile App Development" style="max-width: 100%; height: auto; border-radius: 10px; margin-top: 10px;"> </a> </div> </div> </div> <div class="tab-content" data-content="2" style="display:none;"> <div class="two-column"> <div class="left-column"> <img src="https://dev.icreativesol.com/wp-content/uploads/2025/04/mobile-group-1.webp" alt="Sample Image" /> </div> <div class="right-column"> <h2 class="grad-title">SEARCH ENGINE OPTIMIZATION</h2> <p>The upsurge of the mobile game app industry is generating high revenues by capturing a large-scale market of game players. Building a game app that provides financial aid requires high-profile game app developers who help you discover unwavering strategies for game design and development that not only exist for entertainment but also generate hefty revenues for investors.</p> <a href="https://www.your-link.com" target="_blank"> <img class="anim-arrow-icon" src="https://dev.icreativesol.com/wp-content/uploads/2025/04/white-btn.svg" alt="Mobile App Development" style="max-width: 100%; height: auto; border-radius: 10px; margin-top: 10px;"> </a> </div> </div> </div> </div> </div> </div> </div> <script src="https://cdn.jsdelivr.net/npm/swiper@9/swiper-bundle.min.js"></script> <script> // Initialize Swiper const swiper = new Swiper(".custom-home-slider .swiper", { speed: 600, slidesPerView: 1, spaceBetween: 30, navigation: { nextEl: ".custom-home-slider .swiper-button-next", prevEl: ".custom-home-slider .swiper-button-prev", }, on: { slideChange: () => { updateTitleTabs(swiper.activeIndex); updateProgressBar(swiper.activeIndex); resetInnerTabs(swiper.activeIndex); }, }, }); // Elements references const titleTabs = document.querySelectorAll(".custom-home-slider .slide-title-tab"); const progressBar = document.querySelector(".custom-home-slider .progress-bar"); const swiperSlides = document.querySelectorAll(".custom-home-slider .swiper-slide"); // Update big slide title tabs (left, center, right, hidden) function updateTitleTabs(activeIndex) { const total = titleTabs.length; titleTabs.forEach((tab, idx) => { tab.classList.remove("left", "center", "right", "hidden"); if (idx === activeIndex) { tab.classList.add("center"); } else if ( (activeIndex === 0 && idx === 1) || // Innovation center => Design left (activeIndex === 1 && idx === 0) || // Design center => Innovation left (activeIndex === 2 && idx === 1) // Marketing center => Design left ) { tab.classList.add("left"); } else if ( (activeIndex === 0 && idx === 2) || // Innovation center => Marketing right (activeIndex === 1 && idx === 2) || // Design center => Marketing right (activeIndex === 2 && idx === 0) // Marketing center => Innovation right ) { tab.classList.add("right"); } else { tab.classList.add("hidden"); } }); } // Initially call it updateTitleTabs(swiper.activeIndex); // Clicking big slide title tabs moves swiper slide titleTabs.forEach((tab, index) => { tab.addEventListener("click", () => { swiper.slideTo(index); }); }); // Update progress bar width according to slide index function updateProgressBar(activeIndex) { const totalSlides = swiperSlides.length; const progressPercent = ((activeIndex + 1) / totalSlides) * 100; progressBar.style.width = progressPercent + "%"; } // Initial progress bar updateProgressBar(swiper.activeIndex); // Handle inner tabs switching inside each slide swiperSlides.forEach((slide) => { const tabs = slide.querySelectorAll(".tab"); const contents = slide.querySelectorAll(".tab-content"); tabs.forEach((tab) => { tab.addEventListener("click", () => { // Remove active from all tabs in this slide tabs.forEach((t) => t.classList.remove("active")); // Hide all content in this slide contents.forEach((content) => (content.style.display = "none")); // Activate clicked tab tab.classList.add("active"); // Show related content const dataTab = tab.getAttribute("data-tab"); const contentToShow = slide.querySelector(`.tab-content[data-content="${dataTab}"]`); if (contentToShow) contentToShow.style.display = "flex"; }); }); }); // When slide changes, reset inner tabs to first tab active + content visible function resetInnerTabs(activeIndex) { swiperSlides.forEach((slide, idx) => { const tabs = slide.querySelectorAll(".tab"); const contents = slide.querySelectorAll(".tab-content"); if (idx === activeIndex) { // Show first tab and content in active slide tabs.forEach((tab, i) => { tab.classList.toggle("active", i === 0); }); contents.forEach((content, i) => { content.style.display = i === 0 ? "flex" : "none"; }); } else { // Hide all contents in inactive slides contents.forEach((content) => (content.style.display = "none")); tabs.forEach((tab) => tab.classList.remove("active")); } }); } // Reset inner tabs on load resetInnerTabs(swiper.activeIndex); </script> </body> </html>
<?php function solutionsliderloop() { $arg = array( 'post_type' => 'solution', 'posts_per_page' => 8, 'order' => 'Asc', ); $solutionPost = new WP_Query($arg); if ($solutionPost->have_posts()): ?> <div class="solution-swiper-wrapper"> <div class="swiper solutionswiper"> <div class="swiper-wrapper"> <?php while ($solutionPost->have_posts()): $solutionPost->the_post(); ?> <div class="swiper-slide <?php the_field('class'); ?>"> <div class="solutionswiper-inner"> <div class="swiper-number"> <h3><?php the_title(); ?></h3> </div> <div class="swiper-content"> <?php the_content(); ?> </div> </div> </div> <?php endwhile; ?> </div> <img src="<?php echo get_stylesheet_directory_uri(); ?>/img/solutioncircle.svg" alt="" class="circle-img"> <img src="<?php echo get_stylesheet_directory_uri(); ?>/img/solutiondrone.svg" alt="" class="rotatedroneimg-img"> </div> <div class="swiper-button-next"> <img src="<?php echo get_stylesheet_directory_uri(); ?>/img/solutionright.svg" alt=""> </div> <div class="swiper-button-prev"> <img src="<?php echo get_stylesheet_directory_uri(); ?>/img/solutionleft.svg" alt=""> </div> </div> <?php endif; wp_reset_postdata(); } add_shortcode('solutionslider' var mySwiper = new Swiper('.solutionswiper', { loop: true, slidesPerView: 1.7, navigation: { nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev', }, breakpoints: { 10: { slidesPerView: 1, }, 620: { slidesPerView: 1.7, }, }, on: { slideChange: function () { let currentIndex = mySwiper.realIndex; const droneImage = document.querySelector(".rotatedroneimg-img"); const circleImage = document.querySelector(".circle-img"); const getResponsiveValues = () => { if (window.innerWidth <= 420) { return { drone: [ { x: 135, y: -37 }, // Slide 1 { x: 296, y: 104 }, // Slide 2 { x: -66, y: 310 }, // Slide 3 { x: -70, y: 90 } // Slide 4 ], circle: [ { x: 0, y: -3, scale: 1 }, // Slide 1 { x: 4, y: 0, scale: 1 }, // Slide 2 { x: 4, y: -3, scale: 1 },// Slide 3 { x: 6, y: -1, scale: 1 } // Slide 4 ] }; } else if (window.innerWidth <= 480) { return { drone: [ { x: 111, y: -49 }, // Slide 1 { x: 280, y: 104 }, // Slide 2 { x: -66, y: 310 }, // Slide 3 { x: -70, y: 90 } // Slide 4 ], circle: [ { x: 0, y: -3, scale: 1 }, // Slide 1 { x: 6, y: 0, scale: 1 }, // Slide 2 { x: 4, y: -3, scale: 1 },// Slide 3 { x: 6, y: -1, scale: 1 } // Slide 4 ] }; } else if (window.innerWidth <= 620) { return { drone: [ { x: 111, y: -49 }, // Slide 1 { x: 280, y: 104 }, // Slide 2 { x: -66, y: 310 }, // Slide 3 { x: -70, y: 90 } // Slide 4 ], circle: [ { x: 0, y: -3, scale: 1 }, // Slide 1 { x: 6, y: 0, scale: 1 }, // Slide 2 { x: 4, y: -3, scale: 1 },// Slide 3 { x: 6, y: -1, scale: 1 } // Slide 4 ] }; } else if (window.innerWidth <= 767) { return { drone: [ { x: 114, y: 40 }, // Slide 1 { x: 239, y: 175 }, // Slide 2 { x: -75, y: 350 }, // Slide 3 { x: -52, y: 158 } // Slide 4 ], circle: [ { x: 0, y: -3, scale: 1 }, // Slide 1 { x: 12, y: 0, scale: 1 }, // Slide 2 { x: 14, y: -3, scale: 1 },// Slide 3 { x: 16, y: -5, scale: 1 } // Slide 4 ] }; } else if (window.innerWidth <= 1024) { return { drone: [ { x: 114, y: 40 }, // Slide 1 { x: 239, y: 175 }, // Slide 2 { x: -75, y: 350 }, // Slide 3 { x: -52, y: 158 } // Slide 4 ], circle: [ { x: 0, y: -3, scale: 1 }, // Slide 1 { x: 12, y: 0, scale: 1 }, // Slide 2 { x: 14, y: -3, scale: 1 },// Slide 3 { x: 16, y: -5, scale: 1 } // Slide 4 ] }; } else { return { drone: [ { x: 114, y: 40 }, // Slide 1 { x: 303, y: 195 }, // Slide 2 { x: -62, y: 400 }, // Slide 3 { x: -52, y: 158 } // Slide 4 ], circle: [ { x: 0, y: -3, scale: 1 }, // Slide 1 { x: 12, y: 0, scale: 1 }, // Slide 2 { x: 9, y: -3, scale: 1 },// Slide 3 { x: 9, y: -3, scale: 1 } // Slide 4 ] }; } }; const { drone, circle } = getResponsiveValues(); if (droneImage) { const translationDrone = drone[currentIndex % drone.length]; droneImage.style.transform = `translate(${translationDrone.x}%, ${translationDrone.y}%) scale(1.1)`; droneImage.style.transition = "transform 0.5s ease"; } if (circleImage) { const translationCircle = circle[currentIndex % circle.length]; circleImage.style.transform = `translate(${translationCircle.x}%, ${translationCircle.y}%) scale(${translationCircle.scale})`; circleImage.style.transition = "transform 0.5s ease"; /* Theme Name: Woodmart Child Description: Woodmart Child Theme Author: XTemos Author URI: http://xtemos.com Template: woodmart Version: 1.0.0 Text Domain: woodmart */ .wp-dark-mode-floating-switch.wp-dark-mode-ignore.wp-dark-mode-animation.wp-dark-mode-animation-bounce { display: none !important; } .main-page-wrapper { margin: 0 !important; padding: 0 !important; background-color: black !important; } .whb-header { background-color: black; margin-bottom: 0px !important; } div#mainbanner { height: 100%; min-height: 780px; display: flex; align-items: center; margin-top: -70px; z-index: 9999; } .video-background { position: absolute; top: -158px; left: 0; width: 100%; height: 100%; opacity: 0.5; } .video-background video { width: 100%; height: 100%; object-fit: cover; min-height: 720px; } .site-logo img { max-height: 100px !important; width: 100%; max-width: 290px !important; transform: none !important; perspective: none !important; height: 100% !important; padding: 0 !important; } a.wd-logo.wd-sticky-logo { margin-top: -15px !important; /* transition: none; */ } .whb-general-header { height: 110px !important; display: flex; align-items: center; /* backdrop-filter: blur(30px); */ background-color: rgba(255, 255, 255, 0.04) !important; } .wd-prefooter { padding-bottom: 0 !important; } ul#menu-mainmenu li a { text-transform: capitalize; color: #fff; font-family: "Karla"; font-size: 20px; font-style: normal; font-weight: 400; line-height: normal; opacity: 0.6; } ul#menu-mainmenu li { margin-left: 10px; } ul#menu-mainmenu li a:hover { opacity: 2; } ul#menu-mainmenu li.current-menu-item a { opacity: 2; } .mainbtn { text-transform: capitalize; color: #fff !important; font-family: "Karla"; font-size: 20px; font-style: normal; font-weight: 300; line-height: normal; border-radius: 500px; background: linear-gradient(92deg, #004999 -19.88%, #00efeb 107.62%); box-shadow: none !important; } .homecontentbox .info-box-inner { width: 70%; margin: 0 auto; font-weight: 300; } .homecontentbox { margin: 60px 0 0 !important; } div#togglebutton a { background: linear-gradient(92deg, #004999 -19.88%, #00efeb 107.62%) !important; color: #fff !important; font-size: 12px !important; border: none !important; -webkit-animation: bounce 2s infinite; animation: bounce 2s infinite; } div#togglebutton a:hover { -webkit-animation: none; animation: none; } div#togglebutton a .vc_btn3-icon { font-size: 23px !important; height: 11px !important; line-height: 14px !important; font-weight: 600 !important; } @-webkit-keyframes bounce { 0%, 20%, 50%, 80%, 100% { transform: translateY(0); } 40% { transform: translateY(-30px); } 60% { transform: translateY(-15px); } } @keyframes bounce { 0%, 20%, 50%, 80%, 100% { transform: translateY(0); } 40% { transform: translateY(-30px); } 60% { transform: translateY(-15px); } } div#togglebutton { position: relative; top: 80px; margin-bottom: 0 !important; z-index: 9999; } div#aboutsec { padding: 100px 0; } #leftimgsect { display: flex; align-items: center; position: relative !important; } #leftimgsect2 { display: flex; align-items: center; } #rightimgsect { display: flex; align-items: center; } .drone-sect { padding: 100px 0; } .whb-main-header { background: rgba(255, 255, 255, 0.04); backdrop-filter: blur(30px); background-color: rgba(255, 255, 255, 0.04) !important; box-shadow: none !important; z-index: 9999999 !important; } .card-content { height: 100%; min-height: 220px; padding: 30px 20px 0; } .card-description p { color: #fff; font-family: "Karla"; font-size: 20px; font-style: normal; font-weight: 400; margin: 0 !important; line-height: 23px; } .card-description p { color: #fff; font-family: "Karla"; font-size: 20px; font-style: normal; font-weight: 300; margin: 0 !important; line-height: 26px; } .service-card-sect .card img { width: 100%; } .service-card-sect .card { background-color: #202020; color: #fff; border-radius: 30px; margin-bottom: 40px; border: none !important; transition: 0.3s all; cursor: pointer; } footer.footer-container.color-scheme-dark { background: linear-gradient(92deg, #004999 -19.88%, #00efeb 107.62%); box-shadow: 0px 0px 16px 0px rgba(0, 0, 0, 0.1); padding: 100px 0 0; } .service-card-sect .card:hover { background: linear-gradient(92deg, #004999 -19.88%, #00efeb 107.62%) !important; } div#leftimgsect:before { content: ""; position: absolute; left: 0px; bottom: 0; width: 50%; height: 510px; background-image: url(img/leftbefore.png); background-size: 95%; background-repeat: no-repeat; background-position: left; } div#leftimgsect2:before { content: ""; position: absolute; left: 0; bottom: -70px; width: 50%; height: 520px; background-image: url(img/leftbefore.png); background-size: 100% 66%; background-repeat: no-repeat; background-position: left; } div#rightimgsect:before { content: ""; position: absolute; right: 0; bottom: 0; width: 50%; height: 490px; background-image: url(img/rightbefore.png); background-size: 120%; background-repeat: no-repeat; background-position: left; } div#leftimgsect2 .info-box-wrapper { padding-left: 70px; } div#leftimgsect .info-box-wrapper { padding-left: 40px; } h2#wework { font-size: 50px; font-style: normal; font-weight: 700; line-height: normal; margin-bottom: 90px; } div#buttonimg { margin: 0 -6px; } div#mobilebtnsect { padding: 70px 0 140px; } div#mobilebtnsect h2#wework { margin-bottom: 50px; } .service-card-sect .card .card-content h2 { font-family: "Karla"; font-size: 34px; font-style: normal; font-weight: 700; line-height: normal; color: #fff; } div#servicesect { padding: 50px 0 50px; } div#mobileimg1 img { width: 100%; max-width: 400px !important; } div#mobileimg2 img { width: 100%; max-width: 400px !important; } .simple-box .info-box-title { line-height: 45px !important; margin-bottom: 25px !important; } div#mobileimg3 img { width: 100%; max-width: 380px !important; } div#footerlogo img { width: 100%; } div#copyrighttext p { margin: 0 !important; color: #fff; font-size: 20px; } .newsletter-signup h3 { color: #fff; font-size: 24px; font-style: normal; font-weight: 600; line-height: normal; text-transform: uppercase; margin-bottom: 50px; } .newsletter-signup { text-align: center; } h2#footerhead { color: #fff; font-family: "Karla"; font-size: 20px; font-style: normal; font-weight: 600; line-height: normal; margin-bottom: 40px; } .newsletter-input input.wpcf7-form-control.wpcf7-text.wpcf7-validates-as-required { border: none !important; color: #fff; padding: 0; } div#footerlogo { margin-bottom: 80px; } .newsletter-input input.wpcf7-form-control.wpcf7-text.wpcf7-validates-as-required::placeholder { color: #fff; font-family: "BAGOS"; font-size: 18px; font-style: normal; font-weight: 400; line-height: normal; opacity: 0.7; } .newsletter-input input.wpcf7-form-control.wpcf7-text.wpcf7-validates-as-required::focus { color: #fff; font-family: "BAGOS"; font-size: 18px; font-style: normal; font-weight: 400; line-height: normal; opacity: 0.7; } .newsletter-input input.news-send { border-radius: 10px; background: #fff; font-size: 16px; font-style: normal; font-weight: 500; line-height: normal; color: #004999; width: 20%; padding: 12px; height: 50px !important; } .newsletter-signup span.wpcf7-not-valid-tip { position: absolute; margin: 0 auto; left: 0; right: 0; } footer .screen-reader-response { display: none !important; } .newsletter-input p { width: 60%; margin: 0 auto; display: flex; text-align: center; justify-content: space-between; border-bottom: 1px solid #fff; padding-bottom: 18px; } .newsletter-input span.wpcf7-spinner { display: none !important; } span.wpcf7-form-control-wrap { width: 100%; } div#footerrow { padding: 80px 0 40px; } div#footermenu ul li a { color: #fff; font-family: "BAGOS"; font-size: 18px; font-style: normal; font-weight: 400; line-height: normal; } div#footermenu ul li span.list-content { color: #fff; font-family: "BAGOS"; font-size: 18px; font-style: normal; font-weight: 400; line-height: normal; } div#footermenu ul li { padding-bottom: 8px; } div#footermenu ul.wd-list-type-icon { margin-bottom: 10px !important; } div#footermenu ul li span.list-icon { font-size: 24px; } .galleryswiper { width: 1055px; padding-top: 50px; padding-bottom: 50px; } .galleryswiper .swiper-slide { width: 345px; } .galleryswiper .swiper-slide img.slide-img { width: 100%; height: 500px; object-fit: cover; border-radius: 20px; border: 4px solid #004999; position: relative; } .social-links span.wd-label { font-size: 22px; width: 100%; } .galleryswiper .swiper-slide { border-radius: 20px; } .galleryswiper .swiper-slide.swiper-slide-active:before { display: none !important; } .galleryswiper .swiper-slide:before { content: ""; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: linear-gradient(0deg, rgba(255, 255, 255, 0.35) 0%, rgba(255, 255, 255, 0.35) 100%), lightgray; z-index: 999999; width: 100%; height: 100%; opacity: 0.4; border-radius: 20px; transition: 0.3s ease-in; } .gallery-swiper-wrapper .swiper-button-next:after { content: "" !important; font-size: 0 !important; } .gallery-swiper-wrapper .swiper-button-prev:after { content: "" !important; font-size: 0 !important; } .gallery-swiper-wrapper .swiper-button-next, .gallery-swiper-wrapper .swiper-button-prev { width: 50px; } .gallery-swiper-wrapper .swiper-button-next { transform: translate(-40px, 52px); } .gallery-swiper-wrapper .swiper-button-prev { transform: translate(40px, 50px); } div#galleryslidersect { background-color: #202020; padding: 100px 0 60px; } .faqcontbox { flex-direction: column-reverse !important; } div#questionsect .faqcontbox svg { width: 530px !important; height: 350px !important; object-fit: cover; margin-left: -120px; } div#questionsect { padding: 130px 0 0; } div#questionsect .info-svg-wrapper.info-icon { width: 100% !important; height: 100% !important; } .faq-wrapper .accordion-button:not(.collapsed) { background-color: #ffffff00 !important; border-radius: 13px !important; color: #fff; padding-bottom: 20px !important; } .faq-wrapper button.accordion-button.collapsed { border-radius: 30px !important; } .faq-wrapper .accordion-button { background-color: #202020 !important; box-shadow: none !important; border: none !important; padding: 32px 40px; color: #fff; font-family: "Karla"; font-size: 22px; font-weight: 400; text-align: left; display: flex; justify-content: flex-start; } .faq-wrapper .accordion-button span { margin-left: 22px; text-transform: math-auto; } .faq-wrapper .accordion-item { background-color: #202020 !important; border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 13px !important; margin-bottom: 15px; } .faq-wrapper .accordion-body { background-color: #202020 !important; padding: 8px 28px 30px; color: #fff; border-radius: 13px; } .accordion-body p { margin: 0; font-family: "Karla"; font-size: 18px; font-weight: 400; border-top: 1px solid rgba(255, 255, 255, 0.2); padding-top: 18px; } .faqcontbox .info-box-inner { width: 75%; } .faq-wrapper .accordion-header { background-color: #ffffff00 !important; border-radius: 13px !important; } .faq-wrapper .accordion-button.collapsed::before { content: "\002B"; } .accordion-button:not(.collapsed)::after { display: none !important; } .faq-wrapper .accordion-button::before { content: "\2212"; font-size: 38px; position: absolute; left: 20px; color: #fff; background-color: transparent !important; border: none !important; width: 40px; height: 40px; display: flex; justify-content: center; align-items: center; border-radius: 7px; font-weight: 300; } .error404 .main-page-wrapper { background-image: url(img/404.png); background-repeat: no-repeat; background-size: cover; background-position: bottom; } .page-id-164 .main-page-wrapper { background-image: url(img/404.png); background-repeat: no-repeat; background-size: cover; background-position: bottom; } .error404 .main-page-wrapper .site-content.col-12 { padding: 116px 0 90px; } .error404 .page-header:before { font-weight: 500 !important; } .error404 .page-content p { text-align: center; font-family: "Karla"; font-size: 34px !important; font-style: normal; font-weight: 400; color: #fff; line-height: 38px; margin: 70px 0 10px; } a.erorrbutton { text-transform: capitalize; color: #fff !important; font-family: "Karla"; font-size: 20px; font-style: normal; font-weight: 300; line-height: normal; border-radius: 500px; background: linear-gradient(92deg, #004999 -19.88%, #00efeb 107.62%); box-shadow: none !important; padding: 14px 40px; position: relative; top: 50px; } div#thankyoubtn a { text-transform: capitalize; color: #fff !important; font-family: "Karla"; font-size: 20px; font-style: normal; font-weight: 300; line-height: normal; border-radius: 500px; background: linear-gradient(92deg, #004999 -19.88%, #00efeb 107.62%); box-shadow: none !important; padding: 14px 40px; border: none; } .thank-box .info-box-inner { width: 40%; margin: 30px auto 10px; } div#thanksect { height: 100%; display: flex; justify-content: center; align-items: flex-end; min-height: 560px; padding-bottom: 30px; } .page-title { height: 100%; min-height: 340px; padding: 0 !important; display: flex; align-items: flex-end; margin: 0px !important; background-color: transparent !important; } /* .page-title::after { content: ''; position: absolute; width: 100%; height: 300px; bottom: 0; box-shadow: 0px 20px 30px rgba(13, 15, 15, 0.56); background: linear-gradient(0deg, rgba(14, 14, 14, 0.73) 0%, rgba(14, 14, 14, 0.00) 100%); filter: blur(10px); z-index: -1; } */ .page-title .breadcrumbs { display: none; } .contact-box .info-box-inner { width: 77%; margin: 36px 0 26px; } .social-links { padding-top: 24px !important; } .social-links a.wd-social-icon.social-instagram { background: linear-gradient(315deg, #fbe18a 0.96%, #fcbb45 21.96%, #f75274 38.96%, #d53692 52.96%, #8f39ce 74.96%, #5b4fe9 100.96%); border-radius: 15px !important; box-shadow: none !important; margin-right: 20px !important; } div#contactsect .social-links span.wd-icon { font-size: 30px !important; line-height: 0 !important; } div#contactsect .wd-social-icons { display: flex; flex-wrap: wrap; } .social-links a.wd-social-icon.social-youtube { background-color: #ff0000 !important; border-radius: 15px !important; box-shadow: none !important; } .homecontentbox { position: relative; z-index: 9999; } div#lottie-animation svg { width: 770px !important; height: 450px !important; position: relative; right: -120px; } .form-image { text-align: center; } .contact-man-form { border-radius: 20px; background: #202020; position: relative; padding: 30px 30px; top: -30px; } .contact-man-form label { color: #fff; font-family: Karla; font-size: 20px; font-style: normal; font-weight: 400; } .contact-man-form .form-row input { border-radius: 16px !important; background-color: #35363a !important; border: none !important; height: 60px !important; } .contact-man-form .form-row textarea { border-radius: 16px !important; background-color: #35363a !important; border: none !important; height: 150px !important; min-height: 100% !important; } div#contactcol .wpb_wrapper { position: relative; padding: 0 30px 0px; border-top: 0px !important; border-radius: 20px; } div#contactcol .wpb_wrapper:before { content: ""; position: absolute; width: 100%; height: 100%; opacity: 0.6; top: 0; background: linear-gradient(75deg, #004999 -17.88%, #00efeb 110.62%); left: 0px; border-radius: 20px; border: 14px solid #56b9f2; } div#contactsect .icons-size-large .wd-social-icon { width: 60px; height: 60px; display: flex; justify-content: center; align-items: center; margin: 0; } .page-id-177 div#contactsect { padding: 14rem 0 5rem; overflow: hidden; } .page-id-177 div#contactsect:before{ bottom: 150px; } div#contactsect:before { content: ""; position: absolute; left: -40px; width: 780px; height: 690px; background-image: url(img/contact-before.svg); background-size: 90%; z-index: 0; background-repeat: no-repeat; background-position: top; bottom: 270px; } .page-id-177 .main-page-wrapper { background-image: url(img/contactusbg.png); background-repeat: no-repeat; background-size: cover; background-position: top; margin: -100px 0 0 !important; } .page-id-177 .main-page-wrapper .page-title-default .entry-title.title { padding-bottom: 10px; } .form-row-sumbit input { text-transform: capitalize; color: #fff !important; font-family: "Karla"; font-size: 20px; font-style: normal; font-weight: 300; line-height: normal; border-radius: 500px; background: linear-gradient(92deg, #004999 -19.88%, #00efeb 107.62%); box-shadow: none !important; padding: 12px 42px; } div#faqtitttle h1 { color: #fff; text-align: center; font-family: "Karla"; font-size: 60px; font-style: normal; font-weight: 700; line-height: 58px; } div#faqtitttle h1 strong { background: linear-gradient(92deg, #004999 -19.88%, #00efeb 107.62%); background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-family: Karla; } div#faqcontent p { font-family: Karla; font-size: 22px; font-style: normal; font-weight: 400; line-height: normal; color: #fff; margin: 0 auto; width: 50%; } div#faqheader { padding: 100px 0 100px; } .page-id-230 .main-page-wrapper { background-image: url(img/faqbg.png); background-repeat: no-repeat; background-size: 100%; background-position: top; margin: -10px 0 0 !important; } .page-id-183 .main-page-wrapper { background-image: url(img/servicebg.png); background-repeat: no-repeat; background-size: 100%; background-position: top; margin: -10px 0 0 !important; } div#mainfaqsect { padding: 10rem 0 2rem; } .page-id-230 div#contactsect { padding: 17rem 0 0; } div#mainfaqsect .faq-wrapper { width: 80%; margin: 0 auto; } div#faqtitttle h1 strong { font-weight: 700 !important; } div#serviceheader div#faqcontent p { margin: 0; width: 75%; } div#serviceheader div#faqtitttle h1 strong { background: none; color: #56b9f2 !important; -webkit-text-fill-color: #56b9f2 !important; } div#serviceheader { padding: 200px 0; } .service-box { height: 350px; margin-bottom: 35px; border-radius: 16px; position: relative; display: flex; align-items: flex-end; padding: 0px 20px; object-fit: cover; } .service-box-content h2 { color: #fff; font-family: "Karla"; font-style: normal; font-weight: 700; line-height: normal; font-size: 30px; transition: transform 0.3s ease-in-out; margin-bottom: 0 !important; } .service-box-description p { color: #fff; font-family: "Karla"; font-size: 20px; font-style: normal; font-weight: 400; line-height: normal; } .service-box-description { width: 100%; transition: opacity 0.3s ease-in; margin-left: auto; opacity: 0; } .service-box:hover .service-box-description { opacity: 1; } .service-box:hover .service-box-content h2 { transform: translateY(-20px); } div#servicemainsect { padding-top: 80px; } .page-id-183 div#contactsect { padding: 200px 0 100px; } div#galleryheader { padding: 100px 0; } div#galleryheader div#faqcontent p { margin: 0; width: 85%; } .page-id-181 h2#wework { margin-bottom: 35px; } .galleryhome-swiper-wrapper .swiper-slide img { width: 100%; height: 100%; min-height: 540px; object-fit: cover; border-radius: 16px; } div#faqboxcol { padding: 50px 0 0 100px; } .galleryhome-swiper-wrapper { position: relative; } .galleryhome-swiper-wrapper:before { content: ""; position: absolute; width: 550px; height: 530px; opacity: 0.5; background: var(--Gradient-Color, linear-gradient(0deg, rgba(0, 0, 0, 0.2) 0%, rgba(0, 0, 0, 0.2) 100%), linear-gradient(92deg, #ff6801 1.46%, #993e01 84.37%)); filter: blur(155.1724090576172px); z-index: 0; } div#heartimg img { width: 100%; object-fit: cover; max-width: 350px; } div#heartimg { margin: 0 !important; } div#thanksect .vc_column-inner { padding: 0 !important; } div#mobilebtnsect div#appbuttonrow img { position: relative !important; left: 0 !important; } div#appbuttonrow img { width: 100%; max-width: 230px; object-fit: cover; } div#aboutheader { height: 630px; } button#lg-next-1 { position: absolute; } div#lg-outer-1 { z-index: 999999999; } div#lg-backdrop-1 { z-index: 99999999; } .gallery-container { flex-wrap: wrap; display: flex; margin-top: 70px; } .gallery-inner { width: 15%; text-align: center; cursor: pointer; margin: 0 5px 15px; } a.gallery-inner img { width: 100%; max-width: 100%; object-fit: cover; } div#galleryimagessect { padding: 100px 0 100px; } div#aboutheader div#faqcontent p { margin: 0; width: 100%; } div#aboutcontentcol { padding-top: 90px; } div#aboutsecondsect { padding: 100px 0 100px; position: relative; background-image: linear-gradient(349deg, #22272b 7.94%, rgba(14, 14, 14, 0) 72.21%); } .aerial-about { color: #fff; font-family: Karla; font-size: 22px; font-style: normal; font-weight: 400; line-height: 32px; } div#img1 img { width: 100%; max-width: 540px; object-fit: cover; border-radius: 18px; position: relative; } div#img2 img { width: 100%; max-width: 540px; object-fit: cover; border-radius: 18px; z-index: 999; position: relative; } .team-content-box img.info-icon.image-1 { width: 100%; max-width: 140px; object-fit: cover; } .team-content-box .info-box-title { position: absolute; top: 0; } div#leftteamrow { padding: 0 50px 100px; } div#rightteamrow { padding: 0 50px 0; } .team-content-box .info-box-subtitle { padding-top: 60px; } div#teamsect { padding: 150px 0; } div#teamsect:before { content: ""; position: absolute; left: 0; top: 20%; width: 450px; height: 550px; opacity: 0.5; background: var(--Second-Primary-Color, linear-gradient(92deg, #004999 -19.88%, #00efeb 107.62%)); filter: blur(150px); } div#teamsect:after { content: ""; position: absolute; right: 0; bottom: 9%; width: 470px; height: 500px; opacity: 0.5; background: var(--Second-Primary-Color, linear-gradient(92deg, #004999 -19.88%, #00efeb 107.62%)); filter: blur(150px); } div#quipimg img { margin-bottom: -54px; width: 100%; max-width: 960px; object-fit: cover; position: relative; z-index: 99; } .equip-box { position: relative; } div#equipsrows .info-box-inner p { width: 60%; margin: 0 auto; } div#equipsrows { padding-bottom: 20px; } div#equipsect { padding-top: 100px; } div#equipsect:before { content: ""; position: absolute; left: 0; border-radius: 1808px; background: #fff; bottom: -80%; margin: 0 auto; right: 0; width: 1040px; height: 1020px; z-index: 0; } .page-id-23 div#contactsect { padding: 150px 0; } .page-id-296 div#propertinformobileimg img { width: 100%; max-width: 400px; object-fit: cover; } div#employedsect div#appbuttonrow .wpb_wrapper { display: flex; flex-direction: row; justify-content: flex-start; } div#employedsect div#buttonimg { margin: 0px 30px 0 0px; width: fit-content; } div#employedsect h2#wework { margin-bottom: 20px !important; } div#employedsect { height: 100%; min-height: 950px; background-position: center; background-size: 100%; background-repeat: no-repeat; padding-top: 60px; margin-top: 100px; margin-bottom: 100px; } div#employedariellogo { margin-bottom: 10px; } div#employedcol { padding-left: 80px; } div#appfeaturebg { background-size: 100% !important; background-position: bottom; background-repeat: no-repeat; padding-bottom: 30px; margin-bottom: 50px; } div#appfeaturebg:before { content: ""; position: absolute; top: 10%; right: 10%; width: 500px; height: 360px; background-image: url(img/dronecamera.svg); background-position: center; background-size: 100%; background-repeat: no-repeat; } div#mainappimg img { width: 100%; max-width: 350px; object-fit: cover; } div#mainappimg { margin: 0 !important; } div#appfeaturethmubimg img { width: 100%; max-width: 480px; object-fit: cover; } div#appfeaturesect div#faqcontent p { margin: 0; width: 80%; } div#appfeaturesect { padding: 80px 0; } div#mobileappbtnwrapper .wpb_column.vc_column_container.vc_col-sm-6 { width: fit-content; } div#mobileappbtnwrapper img { width: 100%; max-width: 190px; object-fit: cover; } h4#solutionheading { color: #fff; font-family: "Karla"; font-size: 40px; font-style: normal; font-weight: 500; width: 50%; line-height: 46px; } .swiper-number h3 { color: #56b9f2; font-family: "Karla"; font-size: 220px; font-style: normal; font-weight: 500; line-height: 260px; letter-spacing: -7px; } .swiper-content { padding-left: 50px; } .swiper-content p { color: #fff; font-family: "Karla"; font-size: 48px; font-style: normal; font-weight: 600; line-height: 56px; margin: 0; } .solutionswiper-inner { display: flex; align-items: center; } .solution-swiper-wrapper .swiper-button-next:after { content: "" !important; font-size: 0 !important; } .solution-swiper-wrapper .swiper-button-prev:after { content: "" !important; font-size: 0 !important; } div#solutionsect { border-radius: 40px; background: #202020; margin: 0 4px 100px; padding: 70px 0 80px 140px !important; position: relative; } .solution-swiper-wrapper .swiper-button-next, .solution-swiper-wrapper .swiper-button-prev { background-color: #fff; border-radius: 100%; width: 50px; height: 50px; top: 100%; margin-right: 40px; display: flex; align-items: center; justify-content: center; margin-top: 0px; } div#solutionsect .vc_column-inner { padding: 0 !important; } .solution-swiper-wrapper { position: relative; } .solution-swiper-wrapper .swiper-button-prev { right: 70px !important; left: inherit; } .solutionswiper { padding-top: 30px; padding-left: 40px; } .rotatedroneimg-img { transition: transform 0.5s ease; transform-origin: center; } .rotatedroneimg-img:hover { cursor: pointer; } img.circle-img { position: absolute; top: 65px; width: 100%; left: -2px; max-width: 192px; } img.rotatedroneimg-img { position: absolute; top: 20px; width: 48px; } .wd-toolbar.wd-toolbar-label-show.woodmart-toolbar-label-show.woodmart-toolbar { height: 0 !important; display: none !important; } .mobile-nav { z-index: 999999999 !important; width: 450px !important; background-color: #000 !important; /* background: linear-gradient(92deg, #004999 -19.88%, #00efeb 107.62%); */ } .mobile-nav .wd-action-btn.wd-style-text>a:before { display: flex; align-items: center; justify-content: center; width: 0em; height: 0em; font-size: 22px; font-weight: 400; opacity: 2; filter: brightness(6.5); } .mobile-nav .wd-action-btn.wd-style-text>a { position: relative; font-weight: 600; font-size: 0px !important; line-height: 1; color: #f2e0d6; } .wd-header-mobile-nav .wd-tools-icon:before { font-size: 40px !important; } .mobile-nav ul li a { text-transform: capitalize; color: #fff !important; font-family: "Karla"; font-size: 20px; font-style: normal; font-weight: 400; line-height: normal; opacity: 0.6; } .mobile-nav ul li.current-menu-item a { opacity: 2; } .mobile-nav ul li a:hover { opacity: 2; } .wd-nav-mobile li a { border-bottom: none !important; } .mobil
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Ice Cream Hero</title> <style> * { box-sizing: border-box; } body, html { margin: 0; padding: 0; font-family: "Poppins", sans-serif; background: #00aaff; overflow: hidden; } .hero-section { width: 100vw; height: 100vh; position: relative; display: flex; align-items: center; justify-content: space-between; padding: 50px; overflow: hidden; } img.floating.float6.active { left: 1px; } .hero-text { max-width: 40%; color: white; opacity: 0; transform: translateX(-100px); transition: all 1s ease-out; /* Slowed from 1s to 1.8s */ z-index: 3; } .hero-text.show { opacity: 1; transform: translateX(0); } .hero-text h1 { font-size: 3rem; margin-bottom: 1rem; } .hero-text p { font-size: 1.1rem; margin-bottom: 1.5rem; } .btns img { width: 150px; margin-right: 10px; transition: all 0.8s ease; /* Slowed from 0.5s to 0.8s */ } .btns img:hover { transform: scale(1.05); } .main-image { height: 100%; max-height: 90vh; opacity: 0; transform: translateY(80px); position: absolute; right: 50px; transition: all 2.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); /* Slowed from 1.5s to 2.2s */ z-index: 2; } .main-image.loaded { opacity: 1; bottom: 0; left: 38%; transform: translateY(0) translateX(0); } .main-image.active { transform: rotate(5deg); left: 63%; bottom: 0; transition: all 1.5s ease; /* Slowed from 1s to 1.5s */ } .floating { position: absolute; opacity: 0; transform: translateY(80px); transition: all 2.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); } .floating.loaded { opacity: 1; transform: translateY(0); } img.floating.float1.active { left: 61%; top: 4%; } .floating.active { transition: all 1.8s ease; } img.floating.float4.active { bottom: 4%; right: 35%; z-index: 999; } img.floating.float3.active { bottom: 32%; left: 55%; } .float1 { top: 9%; left: 9%; transition-delay: 0.2s; } img.floating.float2.active { top: 8%; right: 14%; } .float2 { top: 13%; right: 28%; transition-delay: 0.3s; width: 80px; } .float3 { bottom: 32%; left: 30%; transition-delay: 0.4s; } .float4 { bottom: 20%; right: 32%; transition-delay: 0.5s; width: 110px; } .float5 { top: 50%; right: 1%; transition-delay: 0.6s; width: 102px; } .float6 { bottom: 4%; left: -2%; transition-delay: 0.7s; width: 190px; } .float7 { bottom: 0px; right: 4%; transition-delay: 0.8s; width: 200px; } </style> </head> <body> <div class="hero-section"> <div class="hero-text"> <h1>ICE CREAM ON THE BOAT</h1> <p> Make your picnic by the lake even more memorable with our on-demand ice cream app. Whether you're relaxing with fam, spending time with friends, or vibing solo – we deliver frozen treats straight to your picnic spot. </p> <div class="btns"> <img src="appstore.png" alt="App Store" /> <img src="playstore.png" alt="Google Play" /> </div> </div> <div id="mainimagebox"> <img src="/images/hands-phone.png" class="main-image" alt="Phone" onload="imageLoaded(this)" /> <img src="/images/cone.png" class="floating float1" onload="imageLoaded(this)" /> <img src="/images/blueberry.png" class="floating float2" onload="imageLoaded(this)" /> <img src="/images/blur-blueberry.png" class="floating float3" onload="imageLoaded(this)" /> <img src="/images/cup.png" class="floating float4" onload="imageLoaded(this)" /> <img src="/images/chocbar.png" class="floating float5" onload="imageLoaded(this)" /> <img src="/images/boat-left.png" class="floating float6" onload="imageLoaded(this)" /> <img src="/images/blur-boat.png" class="floating float7" onload="imageLoaded(this)" /> </div> </div> <script> function imageLoaded(img) { img.classList.add("loaded"); if ( img.classList.contains("main-image") || img.classList.contains("floating") ) { setTimeout(() => { img.classList.add("active"); }, 4000); } } window.addEventListener("DOMContentLoaded", () => { const heroText = document.querySelector(".hero-text"); setTimeout(() => { heroText.classList.add("show"); }, 5000); }); </script> </body> </html>
<head> <meta charset="utf-8" /> <title>My test page</title> </head>
// Total number of reviews for current product [count_reviews add_shortcode('count_reviews', function() { $product_id = get_queried_object_id(); if ( ! $product_id ) { return ''; } $args = array( 'post_type' => 'simple-reviews', 'post_status' => 'publish', 'posts_per_page' => -1, 'meta_query' => array( array( 'key' => 'review_post_id', 'value' => $product_id, 'compare' => '=', ), array( 'key' => 'rating_review', 'value' => '', 'compare' => '!=', ), ), 'fields' => 'ids', ); $query = new WP_Query($args); $total_reviews = count($query->posts); $label = plural_form($total_reviews, 'отзыв', 'отзыва', 'отзывов'); return "{$total_reviews} {$label}"; }); // Функция склонения слов по числам function plural_form($number, $form1, $form2, $form5) { $n = abs($number) % 100; $n1 = $n % 10; if ($n > 10 && $n < 20) return $form5; if ($n1 > 1 && $n1 < 5) return $form2; if ($n1 == 1) return $form1; return $form5; }
import React, { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { McButton, McInput } from '@maersk-global/mds-react-wrapper'; import { McSelect } from '@maersk-global/mds-react-wrapper/components-core/mc-select'; import { McOption } from '@maersk-global/mds-react-wrapper/components-core/mc-option'; import styles from '../styles/CreateRule.module.css'; import data from '../data/PnLGroup.json'; const CreateRules = () => { const navigate = useNavigate(); const [activeTab, setActiveTab] = useState('ruleInfo'); const [ruleData, setRuleData] = useState({ num: '', name: '', desc: '', custRefID: '', ruleGroup: '', isActive: 'Y', pnlGroup: '', }); const [steps, setSteps] = useState([ { stepNo: '', stepName: 'Single Step', StepDesc: '', stepType: 'S', preAggregatorColumns: '', sourceTable: '', sourceFilters: '', joinColumns: '', allocationColumns: '', driverTableID: '', driverWeightColumn: '', driverFilters: '', }, ]); const [errors, setErrors] = useState({ rule: {}, steps: [{}] }); // Extract PnL Group options from JSON, with fallback for empty data const pnlGroups = data.PnLGroups ? Object.keys(data.PnLGroups) : []; // Get Rule Group options based on selected PnL Group, with fallback const ruleGroups = ruleData.pnlGroup && data.PnLGroups[ruleData.pnlGroup] ? data.PnLGroups[ruleData.pnlGroup].RuleGroups || [] : []; const addStep = () => { setSteps((prevSteps) => [ ...prevSteps, { stepNo: '', stepName: 'Single Step', StepDesc: '', stepType: 'S', preAggregatorColumns: '', sourceTable: '', sourceFilters: '', joinColumns: '', allocationColumns: '', driverTableID: '', driverWeightColumn: '', driverFilters: '', }, ]); setErrors((prevErrors) => ({ ...prevErrors, steps: [...prevErrors.steps, {}], })); }; const validateForm = () => { const newErrors = { rule: {}, steps: steps.map(() => ({})) }; let isValid = true; // Validate rule data Object.keys(ruleData).forEach((key) => { if (key !== 'isActive' && !ruleData[key]) { newErrors.rule[key] = 'This field is required'; isValid = false; } }); // Validate steps steps.forEach((step, index) => { const stepErrors = {}; Object.keys(step).forEach((key) => { if (key !== 'stepName' && key !== 'stepType' && !step[key]) { stepErrors[key] = 'This field is required'; isValid = false; } }); newErrors.steps[index] = stepErrors; }); setErrors(newErrors); return isValid; }; const handleInputChange = (e, stepIndex = null) => { const { name, value } = e.target; console.log(`Input changed: ${name} = ${value}${stepIndex !== null ? ` (Step ${stepIndex + 1})` : ''}`); if (stepIndex !== null) { setSteps((prevSteps) => { const newSteps = [...prevSteps]; newSteps[stepIndex] = { ...newSteps[stepIndex], [name]: value }; return newSteps; }); setErrors((prevErrors) => ({ ...prevErrors, steps: prevErrors.steps.map((stepErrors, i) => i === stepIndex ? { ...stepErrors, [name]: '' } : stepErrors ), })); } else { setRuleData((prevData) => ({ ...prevData, [name]: value, ...(name === 'pnlGroup' ? { ruleGroup: '' } : {}), })); setErrors((prevErrors) => ({ ...prevErrors, rule: { ...prevErrors.rule, [name]: '' }, })); } }; const handleSelectChange = (e) => { const { name, value } = e.target; console.log(`Select changed: ${name} = ${value}`); setRuleData((prevData) => ({ ...prevData, [name]: value, ...(name === 'pnlGroup' ? { ruleGroup: '' } : {}), })); setErrors((prevErrors) => ({ ...prevErrors, rule: { ...prevErrors.rule, [name]: '' }, })); }; const handleSave = async () => { if (!validateForm()) { console.log('Validation failed:', errors); alert('Please fill out all required fields.'); return; } // Parse comma-separated columns and filters const parseColumns = (input) => input.split(',').map((item) => item.trim()).filter((item) => item); const parseFilters = (input) => { const filters = input.split(';').map((item) => item.trim()).filter((item) => item); return filters.map((filter) => { const [name, filterType, values] = filter.split(':').map((item) => item.trim()); return { name, filterType, values }; }); }; const ruleJson = { rules: { rule: [ { num: ruleData.num, name: ruleData.name, desc: ruleData.desc, custRefID: ruleData.custRefID, ruleGroup: ruleData.ruleGroup, isActive: ruleData.isActive, Step: steps.map((step, index) => ({ stepNo: step.stepNo || `${ruleData.num}.${index + 1}`, stepName: step.stepName === 'Single Step' ? 'single' : 'multi', StepDesc: step.StepDesc, stepType: step.stepType, isActive: 'Y', SourceTable: { id: '1', Name: step.sourceTable, }, sourceFilters: { columns: parseFilters(step.sourceFilters), }, preAggregator: { columns: parseColumns(step.preAggregatorColumns), }, join: { columns: parseColumns(step.joinColumns), }, allocation: { columns: parseColumns(step.allocationColumns), }, driver: { driverTableID: step.driverTableID, driverWeightColumn: step.driverWeightColumn, driverFilters: { columns: parseFilters(step.driverFilters), }, }, })), }, ], }, }; console.log('Saving Rule Data:', JSON.stringify(ruleJson, null, 2)); try { const response = await fetch('/api/rules', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(ruleJson), }); if (response.ok) { console.log('Rule created successfully'); navigate('/'); } else { console.error('Failed to create rule:', response.statusText); alert('Failed to create rule. Please try again.'); } } catch (error) { console.error('Error during API call:', error); alert('An error occurred while saving the rule.'); } }; const handleCancel = () => { console.log('Cancelling rule creation'); navigate('/'); }; const renderTabContent = () => { console.log('Rendering tab:', activeTab); switch (activeTab) { case 'ruleInfo': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Rule Information</h3> <div className={styles.formGrid}> <div className={styles.gridItem}> <McSelect label="PnL Group" name="pnlGroup" value={ruleData.pnlGroup} optionselected={handleSelectChange} placeholder="Select a PnL Group" required invalid={!!errors.rule.pnlGroup} invalidmessage={errors.rule.pnlGroup} > {pnlGroups.map((group) => ( <McOption key={group} value={group}> {group} </McOption> ))} </McSelect> </div> <div className={styles.gridItem}> <McSelect label="Rule Group" name="ruleGroup" value={ruleData.ruleGroup} optionselected={handleSelectChange} placeholder={ruleGroups.length ? "Select a Rule Group" : "Select a PnL Group first"} required disabled={!ruleData.pnlGroup || !ruleGroups.length} invalid={!!errors.rule.ruleGroup} invalidmessage={errors.rule.ruleGroup} > {ruleGroups.map((group) => ( <McOption key={group} value={group}> {group} </McOption> ))} </McSelect> </div> </div> <div className={styles.inputGroup}> <McInput label="Rule Number" name="num" value={ruleData.num} input={handleInputChange} placeholder="Enter rule number" required invalid={!!errors.rule.num} invalidmessage={errors.rule.num} /> </div> <div className={styles.inputGroup}> <McInput label="Rule Name" name="name" value={ruleData.name} input={handleInputChange} placeholder="Enter rule name" required invalid={!!errors.rule.name} invalidmessage={errors.rule.name} /> </div> <div className={styles.inputGroup}> <McInput label="Description" name="desc" value={ruleData.desc} input={handleInputChange} placeholder="Enter rule description" multiline rows={3} required invalid={!!errors.rule.desc} invalidmessage={errors.rule.desc} /> </div> <div className={styles.inputGroup}> <McInput label="Customer Reference ID" name="custRefID" value={ruleData.custRefID} input={handleInputChange} placeholder="Enter customer reference ID" required invalid={!!errors.rule.custRefID} invalidmessage={errors.rule.custRefID} /> </div> </div> ); case 'step': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Step Information</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4>Step {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Step Number" name="stepNo" value={step.stepNo} input={(e) => handleInputChange(e, index)} placeholder={`Enter step number (e.g., ${ruleData.num}.${index + 1})`} required invalid={!!errors.steps[index].stepNo} invalidmessage={errors.steps[index].stepNo} /> </div> <div className={styles.inputGroup}> <McSelect label="Step Name" name="stepName" value={step.stepName} optionselected={(e) => handleInputChange(e, index)} required placeholder="Select Step Name" invalid={!!errors.steps[index].stepName} invalidmessage={errors.steps[index].stepName} > <McOption value="Single Step">Single Step</McOption> <McOption value="Multi Step">Multi Step</McOption> </McSelect> </div> <div className={styles.inputGroup}> <McInput label="Step Description" name="StepDesc" value={step.StepDesc} input={(e) => handleInputChange(e, index)} placeholder="Enter step description" multiline rows={3} required invalid={!!errors.steps[index].StepDesc} invalidmessage={errors.steps[index].StepDesc} /> </div> <div className={styles.inputGroup}> <McSelect label="Step Type" name="stepType" value={step.stepType} optionselected={(e) => handleInputChange(e, index)} required placeholder="Select a PnL Group" invalid={!!errors.steps[index].stepType} invalidmessage={errors.steps[index].stepType} > <McOption value="S">S</McOption> <McOption value="M">M</McOption> </McSelect> </div> </div> ))} <div className={styles.buttonContainer}> <McButton label="Add Step" appearance="secondary" click={addStep} className={styles.actionButton} /> </div> </div> ); case 'preAggregate': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Pre-Aggregate Columns</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4>Step {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Pre-Aggregator Columns" name="preAggregatorColumns" value={step.preAggregatorColumns} input={(e) => handleInputChange(e, index)} placeholder="Enter columns (comma-separated)" multiline rows={3} required invalid={!!errors.steps[index].preAggregatorColumns} invalidmessage={errors.steps[index].preAggregatorColumns} /> </div> </div> ))} </div> ); case 'source': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Source Information</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4>Step {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Source Table" name="sourceTable" value={step.sourceTable} input={(e) => handleInputChange(e, index)} placeholder="Enter source table name" required invalid={!!errors.steps[index].sourceTable} invalidmessage={errors.steps[index].sourceTable} /> </div> <div className={styles.inputGroup}> <McInput label="Source Filters" name="sourceFilters" value={step.sourceFilters} input={(e) => handleInputChange(e, index)} placeholder="Enter filters (e.g., PNL_LINE:IN:PnL.DVC.214,PnL.DVC.215;MOVE_TYPE:EQ:EX)" multiline rows={3} required invalid={!!errors.steps[index].sourceFilters} invalidmessage={errors.steps[index].sourceFilters} /> </div> </div> ))} </div> ); case 'join': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Join Columns</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4>Step {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Join Columns" name="joinColumns" value={step.joinColumns} input={(e) => handleInputChange(e, index)} placeholder="Enter columns (comma-separated)" multiline rows={3} required invalid={!!errors.steps[index].joinColumns} invalidmessage={errors.steps[index].joinColumns} /> </div> </div> ))} </div> ); case 'allocation': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Allocation Columns</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4>Step {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Allocation Columns" name="allocationColumns" value={step.allocationColumns} input={(e) => handleInputChange(e, index)} placeholder="Enter columns (comma-separated)" multiline rows={3} required invalid={!!errors.steps[index].allocationColumns} invalidmessage={errors.steps[index].allocationColumns} /> </div> </div> ))} </div> ); case 'driver': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Driver Information</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4>Step {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Driver Table ID" name="driverTableID" value={step.driverTableID} input={(e) => handleInputChange(e, index)} placeholder="Enter driver table ID" required invalid={!!errors.steps[index].driverTableID} invalidmessage={errors.steps[index].driverTableID} /> </div> <div className={styles.inputGroup}> <McInput label="Driver Weight Column" name="driverWeightColumn" value={step.driverWeightColumn} input={(e) => handleInputChange(e, index)} placeholder="Enter driver weight column" required invalid={!!errors.steps[index].driverWeightColumn} invalidmessage={errors.steps[index].driverWeightColumn} /> </div> <div className={styles.inputGroup}> <McInput label="Driver Filters" name="driverFilters" value={step.driverFilters} input={(e) => handleInputChange(e, index)} placeholder="Enter filters (e.g., ALLOC_MOVE:IN:GATE-IN,ON-RAIL;MCHE_SHP:NTEQ:0)" multiline rows={3} required invalid={!!errors.steps[index].driverFilters} invalidmessage={errors.steps[index].driverFilters} /> </div> </div> ))} </div> ); default: return <div className={styles.tabContent}>No Tab Selected</div>; } }; return ( <div className={styles.pageWrapper}> <div className={styles.container}> <div className={styles.card}> <div className={styles.buttonContainer}> <McButton label="Back" appearance="neutral" click={handleCancel} className={styles.actionButton} /> <McButton label="Save" appearance="primary" click={handleSave} className={styles.actionButton} /> </div> <div className={styles.tabs}> <button className={`${styles.tabButton} ${activeTab === 'ruleInfo' ? styles.activeTab : ''}`} onClick={() => setActiveTab('ruleInfo')} > Rule Info </button> <button className={`${styles.tabButton} ${activeTab === 'step' ? styles.activeTab : ''}`} onClick={() => setActiveTab('step')} > Step </button> <button className={`${styles.tabButton} ${activeTab === 'preAggregate' ? styles.activeTab : ''}`} onClick={() => setActiveTab('preAggregate')} > Pre-Aggregate </button> <button className={`${styles.tabButton} ${activeTab === 'source' ? styles.activeTab : ''}`} onClick={() => setActiveTab('source')} > Source </button> <button className={`${styles.tabButton} ${activeTab === 'join' ? styles.activeTab : ''}`} onClick={() => setActiveTab('join')} > Join </button> <button className={`${styles.tabButton} ${activeTab === 'allocation' ? styles.activeTab : ''}`} onClick={() => setActiveTab('allocation')} > Allocation </button> <button className={`${styles.tabButton} ${activeTab === 'driver' ? styles.activeTab : ''}`} onClick={() => setActiveTab('driver')} > Driver </button> </div> {renderTabContent()} </div> </div> </div> ); }; export default CreateRules;
import React, { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { McButton, McInput } from '@maersk-global/mds-react-wrapper'; import { McSelect } from '@maersk-global/mds-react-wrapper/components-core/mc-select'; import { McOption } from '@maersk-global/mds-react-wrapper/components-core/mc-option'; import styles from '../styles/CreateRule.module.css'; import data from '../data/PnLGroup.json'; const CreateRules = () => { const navigate = useNavigate(); const [activeTab, setActiveTab] = useState('ruleInfo'); const [ruleData, setRuleData] = useState({ num: '', name: '', desc: '', custRefID: '', ruleGroup: '', isActive: 'Y', pnlGroup: '', }); const [steps, setSteps] = useState([ { stepNo: '', stepName: 'Single Step', StepDesc: '', stepType: 'S', preAggregatorColumns: '', sourceTable: '', sourceFilters: '', joinColumns: '', allocationColumns: '', driverTableID: '', driverWeightColumn: '', driverFilters: '', }, ]); const [errors, setErrors] = useState({ rule: {}, steps: [{}] }); // Extract PnL Group options from JSON, with fallback for empty data const pnlGroups = data.PnLGroups ? Object.keys(data.PnLGroups) : []; // Get Rule Group options based on selected PnL Group, with fallback const ruleGroups = ruleData.pnlGroup && data.PnLGroups[ruleData.pnlGroup] ? data.PnLGroups[ruleData.pnlGroup].RuleGroups || [] : []; const addStep = () => { setSteps((prevSteps) => [ ...prevSteps, { stepNo: '', stepName: '', StepDesc: '', stepType: '', preAggregatorColumns: '', sourceTable: '', sourceFilters: '', joinColumns: '', allocationColumns: '', driverTableID: '', driverWeightColumn: '', driverFilters: '', }, ]); setErrors((prevErrors) => ({ ...prevErrors, steps: [...prevErrors.steps, {}], })); }; const validateForm = () => { const newErrors = { rule: {}, steps: steps.map(() => ({})) }; let isValid = true; // Validate rule data (all fields are mandatory) Object.keys(ruleData).forEach((key) => { if (!ruleData[key]) { newErrors.rule[key] = 'This field is required'; isValid = false; } }); // Validate steps (all fields are mandatory) steps.forEach((step, index) => { const stepErrors = {}; Object.keys(step).forEach((key) => { if (!step[key]) { stepErrors[key] = 'This field is required'; isValid = false; } }); newErrors.steps[index] = stepErrors; }); setErrors(newErrors); return isValid; }; const handleInputChange = (e, stepIndex = null) => { const { name, value } = e.target; console.log(`Input changed: ${name} = ${value}${stepIndex !== null ? ` (Step ${stepIndex + 1})` : ''}`); if (stepIndex !== null) { setSteps((prevSteps) => { const newSteps = [...prevSteps]; newSteps[stepIndex] = { ...newSteps[stepIndex], [name]: value }; return newSteps; }); setErrors((prevErrors) => ({ ...prevErrors, steps: prevErrors.steps.map((stepErrors, i) => i === stepIndex ? { ...stepErrors, [name]: '' } : stepErrors ), })); } else { setRuleData((prevData) => ({ ...prevData, [name]: value, ...(name === 'pnlGroup' ? { ruleGroup: '' } : {}), })); setErrors((prevErrors) => ({ ...prevErrors, rule: { ...prevErrors.rule, [name]: '' }, })); } }; const handleSelectChange = (e) => { const { name, value } = e.target; console.log(`Select changed: ${name} = ${value}`); setRuleData((prevData) => ({ ...prevData, [name]: value, ...(name === 'pnlGroup' ? { ruleGroup: '' } : {}), })); setErrors((prevErrors) => ({ ...prevErrors, rule: { ...prevErrors.rule, [name]: '' }, })); }; const handleSave = async () => { if (!validateForm()) { console.log('Validation failed:', JSON.stringify(errors, null, 2)); alert('Please fill out all required fields.'); return; } // Parse comma-separated columns and filters const parseColumns = (input) => input.split(',').map((item) => item.trim()).filter((item) => item); const parseFilters = (input) => { const filters = input.split(';').map((item) => item.trim()).filter((item) => item); return filters.map((filter) => { const [name, filterType, values] = filter.split(':').map((item) => item.trim()); return { name, filterType, values }; }); }; const ruleJson = { rules: { rule: [ { num: ruleData.num, name: ruleData.name, desc: ruleData.desc, custRefID: ruleData.custRefID, ruleGroup: ruleData.ruleGroup, isActive: ruleData.isActive, Step: steps.map((step, index) => ({ stepNo: step.stepNo || `${ruleData.num}.${index + 1}`, stepName: step.stepName === 'Single Step' ? 'single' : 'multi', StepDesc: step.StepDesc, stepType: step.stepType, isActive: 'Y', SourceTable: { id: '1', Name: step.sourceTable, }, sourceFilters: { columns: parseFilters(step.sourceFilters), }, preAggregator: { columns: parseColumns(step.preAggregatorColumns), }, join: { columns: parseColumns(step.joinColumns), }, allocation: { columns: parseColumns(step.allocationColumns), }, driver: { driverTableID: step.driverTableID, driverWeightColumn: step.driverWeightColumn, driverFilters: { columns: parseFilters(step.driverFilters), }, }, })), }, ], }, }; console.log('Saving Rule Data:', JSON.stringify(ruleJson, null, 2)); try { const response = await fetch('/api/rules', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: JSON.stringify(ruleJson), }); if (response.ok) { console.log('Rule created successfully'); alert('Rule created successfully!'); navigate('/'); } else { const errorText = await response.text(); console.error('Failed to create rule:', response.status, errorText); alert(`Failed to create rule: ${errorText || response.statusText}`); } } catch (error) { console.error('Error during API call:', error.message); alert('An error occurred while saving the rule. Please try again.'); } }; const handleCancel = () => { console.log('Cancelling rule creation'); navigate('/'); }; const renderTabContent = () => { console.log('Rendering tab:', activeTab); switch (activeTab) { case 'ruleInfo': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Rule Information</h3> <div className={styles.formGrid}> <div className={styles.gridItem}> <McSelect label="PnL Group" name="pnlGroup" value={ruleData.pnlGroup} optionselected={handleSelectChange} placeholder="Select a PnL Group" required invalid={!!errors.rule.pnlGroup} invalidmessage={errors.rule.pnlGroup} > {pnlGroups.map((group) => ( <McOption key={group} value={group}> {group} </McOption> ))} </McSelect> </div> <div className={styles.gridItem}> <McSelect label="Rule Group" name="ruleGroup" value={ruleData.ruleGroup} optionselected={handleSelectChange} placeholder={ruleGroups.length ? "Select a Rule Group" : "Select a PnL Group first"} required disabled={!ruleData.pnlGroup || !ruleGroups.length} invalid={!!errors.rule.ruleGroup} invalidmessage={errors.rule.ruleGroup} > {ruleGroups.map((group) => ( <McOption key={group} value={group}> {group} </McOption> ))} </McSelect> </div> </div> <div className={styles.inputGroup}> <McInput label="Rule Number" name="num" value={ruleData.num} input={handleInputChange} placeholder="Enter rule number" required invalid={!!errors.rule.num} invalidmessage={errors.rule.num} /> </div> <div className={styles.inputGroup}> <McInput label="Rule Name" name="name" value={ruleData.name} input={handleInputChange} placeholder="Enter rule name" required invalid={!!errors.rule.name} invalidmessage={errors.rule.name} /> </div> <div className={styles.inputGroup}> <McInput label="Description" name="desc" value={ruleData.desc} input={handleInputChange} placeholder="Enter rule description" multiline rows={3} required invalid={!!errors.rule.desc} invalidmessage={errors.rule.desc} /> </div> <div className={styles.inputGroup}> <McInput label="Customer Reference ID" name="custRefID" value={ruleData.custRefID} input={handleInputChange} placeholder="Enter customer reference ID" required invalid={!!errors.rule.custRefID} invalidmessage={errors.rule.custRefID} /> </div> <div className={styles.inputGroup}> <McSelect label="Is Active" name="isActive" value={ruleData.isActive} optionselected={handleSelectChange} required invalid={!!errors.rule.isActive} invalidmessage={errors.rule.isActive} > <McOption value="Y">Yes</McOption> <McOption value="N">No</McOption> </McSelect> </div> </div> ); case 'step': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Step Information</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4>Step {index + 1}</h4> <div className={styles.inputGroup}> <McInput minutiae label="Step Number" name="stepNo" value={step.stepNo} input={(e) => handleInputChange(e, index)} placeholder={`Enter step number (e.g., ${ruleData.num}.${index + 1})`} required invalid={!!errors.steps[index].stepNo} invalidmessage={errors.steps[index].stepNo} /> </div> <div className={styles.inputGroup}> <McSelect label="Step Name" name="stepName" value={step.stepName} optionselected={(e) => handleInputChange(e, index)} required placeholder="Select Step Name" invalid={!!errors.steps[index].stepName} invalidmessage={errors.steps[index].stepName} > <McOption value="Single Step">Single Step</McOption> <McOption value="Multi Step">Multi Step</McOption> </McSelect> </div> <div className={styles.inputGroup}> <McInput label="Step Description" name="StepDesc" value={step.StepDesc} input={(e) => handleInputChange(e, index)} placeholder="Enter step description" multiline rows={3} required invalid={!!errors.steps[index].StepDesc} invalidmessage={errors.steps[index].StepDesc} /> </div> <div className={styles.inputGroup}> <McSelect label="Step Type" name="stepType" value={step.stepType} optionselected={(e) => handleInputChange(e, index)} required placeholder="Select Step Type" invalid={!!errors.steps[index].stepType} invalidmessage={errors.steps[index].stepType} > <McOption value="S">S</McOption> <McOption value="M">M</McOption> </McSelect> </div> </div> ))} <div className={styles.buttonContainer}> <McButton label="Add Step" appearance="secondary" click={addStep} className={styles.actionButton} /> </div> </div> ); case 'preAggregate': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Pre-Aggregate Columns</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4>Step {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Pre-Aggregator Columns" name="preAggregatorColumns" value={step.preAggregatorColumns} input={(e) => handleInputChange(e, index)} placeholder="Enter columns (comma-separated)" multiline rows={3} required invalid={!!errors.steps[index].preAggregatorColumns} invalidmessage={errors.steps[index].preAggregatorColumns} /> </div> </div> ))} </div> ); case 'source': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Source Information</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4>Step {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Source Table" name="sourceTable" value={step.sourceTable} input={(e) => handleInputChange(e, index)} placeholder="Enter source table name" required invalid={!!errors.steps[index].sourceTable} invalidmessage={errors.steps[index].sourceTable} /> </div> <div className={styles.inputGroup}> <McInput label="Source Filters" name="sourceFilters" value={step.sourceFilters} input={(e) => handleInputChange(e, index)} placeholder="Enter filters (e.g., PNL_LINE:IN:PnL.DVC.214,PnL.DVC.215;MOVE_TYPE:EQ:EX)" multiline rows={3} required invalid={!!errors.steps[index].sourceFilters} invalidmessage={errors.steps[index].sourceFilters} /> </div> </div> ))} </div> ); case 'join': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Join Columns</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4>Step {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Join Columns" name="joinColumns" value={step.joinColumns} input={(e) => handleInputChange(e, index)} placeholder="Enter columns (comma-separated)" multiline rows={3} required invalid={!!errors.steps[index].joinColumns} invalidmessage={errors.steps[index].joinColumns} /> </div> </div> ))} </div> ); case 'allocation': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Allocation Columns</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4>Step {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Allocation Columns" name="allocationColumns" value={step.allocationColumns} input={(e) => handleInputChange(e, index)} placeholder="Enter columns (comma-separated)" multiline rows={3} required invalid={!!errors.steps[index].allocationColumns} invalidmessage={errors.steps[index].allocationColumns} /> </div> </div> ))} </div> ); case 'driver': return ( <div className={styles.tabContent}> <h3 className={styles.sectionTitle}>Driver Information</h3> {steps.map((step, index) => ( <div key={index} className={styles.stepCase}> <h4>Step {index + 1}</h4> <div className={styles.inputGroup}> <McInput label="Driver Table ID" name="driverTableID" value={step.driverTableID} input={(e) => handleInputChange(e, index)} placeholder="Enter driver table ID" required invalid={!!errors.steps[index].driverTableID} invalidmessage={errors.steps[index].driverTableID} /> </div> <div className={styles.inputGroup}> <McInput label="Driver Weight Column" name="driverWeightColumn" value={step.driverWeightColumn} input={(e) => handleInputChange(e, index)} placeholder="Enter driver weight column" required invalid={!!errors.steps[index].driverWeightColumn} invalidmessage={errors.steps[index].driverWeightColumn} /> </div> <div className={styles.inputGroup}> <McInput label="Driver Filters" name="driverFilters" value={step.driverFilters} input={(e) => handleInputChange(e, index)} placeholder="Enter filters" multiline rows={3} required invalid={!!errors.steps[index].driverFilters} invalidmessage={errors.steps[index].driverFilters} /> </div> </div> ))} </div> ); default: return <div className={styles.tabContent}>No Tab Selected</div>; } }; return ( <div className={styles.pageWrapper}> <div className={styles.container}> <div className={styles.card}> <div className={styles.buttonContainer}> <McButton label="Back" appearance="neutral" click={handleCancel} className={styles.actionButton} /> <McButton label="Save" appearance="primary" click={handleSave} className={styles.actionButton} /> </div> <div className={styles.tabs}> <button className={`${styles.tabButton} ${activeTab === 'ruleInfo' ? styles.activeTab : ''}`} onClick={() => setActiveTab('ruleInfo')} > Rule Info </button> <button className={`${styles.tabButton} ${activeTab === 'step' ? styles.activeTab : ''}`} onClick={() => setActiveTab('step')} > Step </button> <button className={`${styles.tabButton} ${activeTab === 'preAggregate' ? styles.activeTab : ''}`} onClick={() => setActiveTab('preAggregate')} > Pre-Aggregate </button> <button className={`${styles.tabButton} ${activeTab === 'source' ? styles.activeTab : ''}`} onClick={() => setActiveTab('source')} > Source </button> <button className={`${styles.tabButton} ${activeTab === 'join' ? styles.activeTab : ''}`} onClick={() => setActiveTab('join')} > Join </button> <button className={`${styles.tabButton} ${activeTab === 'allocation' ? styles.activeTab : ''}`} onClick={() => setActiveTab('allocation')} > Allocation </button> <button className={`${styles.tabButton} ${activeTab === 'driver' ? styles.activeTab : ''}`} onClick={() => setActiveTab('driver')} > Driver </button> </div> {renderTabContent()} </div> </div> </div> ); }; export default CreateRules;
Launch your own pro-level crypto exchange with Hivelance’s Coinbase Clone Script integrated with AI-powered trading bots. Built for expert traders, it features advanced order types, real-time analytics, top-tier security, and goes live in just 10 days. Fast, customizable, and ready for the bull market! 🔥 Key Features of Coinbase Clone Script ✅ Smart Trading Bots for 24/7 automated trading ✅ Advanced Order Types – Limit, Stop, Market, and more ✅ Real-Time Price Charts & Analytics ✅ High-Speed Matching Engine ✅ Bank-Grade Security Protocols ✅ KYC/AML Integration for Compliance ✅ Multi-Currency & Wallet Support ✅ Responsive Web & Mobile Interface ✅ 100% Customizable & Bug-Free Script ✅ And More 💡 Ideal for entrepreneurs & crypto startups 📞 Contact us now & dominate the crypto trading market! Website - https://www.hivelance.com/coinbase-clone-script Telegram - https://telegram.me/HiveLance Call/WhatsApp - 918438595928
-- ICA_OddTime_PerCard_PerMID_EDC CREATE TABLE team_kingkong.offus_ICA_OddTime_PerCard_PerMID_EDC_breaches AS -- INSERT INTO team_kingkong.offus_ICA_OddTime_PerCard_PerMID_EDC_breaches with offus_txn as (SELECT transactionid, txn_amount, txn_date, paytmmerchantid, txn_timestamp, globalcardindex , case when edc_mid is not null then 'EDC' else 'QR' end as mid_type , merchantcategory, merchantsubcategory, isindian FROM (SELECT DISTINCT pg_mid from cdo.total_offline_merchant_base_snapshot_v3) f INNER join (select distinct transactionid , cast(eventamount as double)/100 as txn_amount , paytmmerchantid , DATE(dl_last_updated) AS txn_date , CAST(velocitytimestamp AS DOUBLE) AS txn_timestamp , globalcardindex , merchantcategory, merchantsubcategory, isindian from cdp_risk_transform.maquette_flattened_offus_snapshot_v3 where dl_last_updated BETWEEN DATE(DATE'2025-02-01' - INTERVAL '1' DAY) AND DATE'2025-02-28' and paymethod in ('CREDIT_CARD','DEBIT_CARD') AND actionrecommended <> 'BLOCK') a on a.paytmmerchantid = f.pg_mid LEFT JOIN (SELECT DISTINCT mid AS edc_mid FROM paytmpgdb.entity_edc_info_snapshot_v3 WHERE terminal_status = 'ACTIVE' AND dl_last_updated >= DATE '2010-01-01') b ON a.paytmmerchantid = b.edc_mid) SELECT * FROM (SELECT A.transactionid, A.txn_amount, A.txn_date, A.paytmmerchantid, A.globalcardindex, A.mid_type, 'ICA_OddTime_PerCard_PerMID_EDC' AS rule_name, A.txn_timestamp , 5000 as per_txn_limit , COUNT(B.transactionid) as txn1_day , 2 as txn1_day_threshold FROM (SELECT * FROM offus_txn WHERE txn_date BETWEEN date '2025-02-01' AND DATE'2025-02-28' AND isindian = 'false' AND HOUR(FROM_UNIXTIME(txn_timestamp / 1000)) BETWEEN 0 AND 4 AND (merchantsubcategory NOT IN ('Restaurant', 'Foodcourt','Restaurants and Bars', 'Fast Food and QSR' , 'Hotel', 'Aviation','Tours and Travel Agency' , 'Pharmacy', 'Hospital','Taxi','Pharmacy', 'Hospital', 'Taxi') OR merchantcategory NOT IN ('Airport','Gas and Petrol')))A LEFT JOIN (SELECT * FROM offus_txn)B ON A.globalcardindex = B.globalcardindex AND A.paytmmerchantid = B.paytmmerchantid AND (A.txn_timestamp - B.txn_timestamp) BETWEEN 0 AND 86400000 -- <= 1day AND A.transactionid <> B.transactionid GROUP BY 1,2,3,4,5,6,7,8) WHERE (txn_amount > per_txn_limit) OR (txn1_day>= txn1_day_threshold) -- LIMIT 100 ;
-- RECHECK -- Merchant_PerTxnLimit_Check -- DROP TABLE team_kingkong.offus_Merchant_PerTxnLimit_Check_breaches; -- CREATE TABLE team_kingkong.offus_Merchant_PerTxnLimit_Check_breaches AS INSERT INTO team_kingkong.offus_Merchant_PerTxnLimit_Check_breaches SELECT transactionid, txn_amount, txn_date, paytmmerchantid, txn_timestamp, paymethod , case when edc_mid is not null then 'EDC' else 'QR' end as mid_type , C.per_txn_limit , C.limit_date FROM (SELECT DISTINCT pg_mid from cdo.total_offline_merchant_base_snapshot_v3) f INNER join (select distinct transactionid , cast(eventamount as double)/100 as txn_amount , paytmmerchantid , globalcardindex , DATE(dl_last_updated) AS txn_date , CAST(velocitytimestamp AS DOUBLE) AS txn_timestamp , paymethod from cdp_risk_transform.maquette_flattened_offus_snapshot_v3 where dl_last_updated BETWEEN DATE(DATE'2025-05-01' - INTERVAL '1' DAY) AND DATE'2025-05-31' and paymethod in ('UPI') AND actionrecommended <> 'BLOCK' AND responsestatus = 'SUCCESS') a on a.paytmmerchantid = f.pg_mid LEFT JOIN (SELECT DISTINCT mid AS edc_mid FROM paytmpgdb.entity_edc_info_snapshot_v3 WHERE terminal_status = 'ACTIVE' AND dl_last_updated >= DATE '2010-01-01') b ON a.paytmmerchantid = b.edc_mid INNER JOIN (SELECT content as mid, CAST(comment AS DOUBLE) as per_txn_limit, "timestamp" as limit_date FROM team_kingkong.merchant_limit_list)C ON a.paytmmerchantid = C.mid AND a.txn_date > DATE(FROM_UNIXTIME(CAST(limit_date AS double) / 1000)) WHERE a.txn_amount > C.per_txn_limit;
-- ICA_OddTime_PerCard_PerMID_EDC DROP TABLE team_kingkong.offus_ICA_OddTime_PerCard_PerMID_EDC_breaches; -- CREATE TABLE team_kingkong.offus_ICA_OddTime_PerCard_PerMID_EDC_breaches AS INSERT INTO team_kingkong.offus_ICA_OddTime_PerCard_PerMID_EDC_breaches with offus_txn as (SELECT transactionid, txn_amount, txn_date, paytmmerchantid, txn_timestamp, globalcardindex , case when edc_mid is not null then 'EDC' else 'QR' end as mid_type , merchantcategory, merchantsubcategory, isindian FROM (SELECT DISTINCT pg_mid from cdo.total_offline_merchant_base_snapshot_v3) f INNER join (select distinct transactionid , cast(eventamount as double)/100 as txn_amount , paytmmerchantid , DATE(dl_last_updated) AS txn_date , CAST(velocitytimestamp AS DOUBLE) AS txn_timestamp , globalcardindex , merchantcategory, merchantsubcategory, isindian from cdp_risk_transform.maquette_flattened_offus_snapshot_v3 where dl_last_updated BETWEEN DATE(DATE'2025-05-01' - INTERVAL '1' DAY) AND DATE'2025-05-31' and paymethod in ('CREDIT_CARD','DEBIT_CARD') AND actionrecommended <> 'BLOCK' AND responsestatus = 'SUCCESS') a on a.paytmmerchantid = f.pg_mid LEFT JOIN (SELECT DISTINCT mid AS edc_mid FROM paytmpgdb.entity_edc_info_snapshot_v3 WHERE terminal_status = 'ACTIVE' AND dl_last_updated >= DATE '2010-01-01') b ON a.paytmmerchantid = b.edc_mid) SELECT * FROM (SELECT A.transactionid, A.txn_amount, A.txn_date, A.paytmmerchantid, A.globalcardindex, A.mid_type, 'ICA_OddTime_PerCard_PerMID_EDC' AS rule_name, A.txn_timestamp , 5000 as per_txn_limit , COUNT(B.transactionid) as txn1_day , 2 as txn1_day_threshold FROM (SELECT * FROM offus_txn WHERE txn_date BETWEEN date '2025-05-01' AND DATE'2025-05-31' AND isindian = 'false' AND HOUR(FROM_UNIXTIME(txn_timestamp / 1000)) BETWEEN 0 AND 4 AND (merchantsubcategory NOT IN ('Restaurant', 'Foodcourt','Restaurants and Bars', 'Fast Food and QSR' , 'Hotel', 'Aviation','Tours and Travel Agency' , 'Pharmacy', 'Hospital','Taxi','Pharmacy', 'Hospital', 'Taxi') OR merchantcategory NOT IN ('Airport','Gas and Petrol')))A LEFT JOIN (SELECT * FROM offus_txn)B ON A.globalcardindex = B.globalcardindex AND A.paytmmerchantid = B.paytmmerchantid AND (A.txn_timestamp - B.txn_timestamp) BETWEEN 0 AND 86400000 -- <= 1day AND A.transactionid <> B.transactionid GROUP BY 1,2,3,4,5,6,7,8) WHERE (txn_amount > per_txn_limit) OR (txn1_day>= txn1_day_threshold) ;
-- CCUPI_vpa_mid_hourly_limit DROP TABLE team_kingkong.offus_CCUPI_vpa_mid_hourly_limit_breaches; -- CREATE TABLE team_kingkong.offus_CCUPI_vpa_mid_hourly_limit_breaches AS INSERT INTO team_kingkong.offus_CCUPI_vpa_mid_hourly_limit_breaches with offus_txn as (SELECT DISTINCT transactionid, txn_amount, txn_date, paytmmerchantid, txn_timestamp, small_vpa , case when edc_mid is not null then 'EDC' else 'QR' end as mid_type FROM (SELECT pg_mid from cdo.total_offline_merchant_base_snapshot_v3) f INNER join (select transactionid , cast(eventamount as double)/100 as txn_amount , paytmmerchantid , DATE(dl_last_updated) AS txn_date , CAST(velocitytimestamp AS DOUBLE) AS txn_timestamp , small_vpa from cdp_risk_transform.maquette_flattened_offus_snapshot_v3 where dl_last_updated BETWEEN DATE(DATE'2025-05-01' - INTERVAL '1' DAY) AND DATE'2025-05-31' AND isupicc = 'true' AND actionrecommended <> 'BLOCK' AND responsestatus = 'SUCCESS') a on a.paytmmerchantid = f.pg_mid LEFT JOIN (SELECT mid AS edc_mid FROM paytmpgdb.entity_edc_info_snapshot_v3 WHERE terminal_status = 'ACTIVE' AND dl_last_updated >= DATE '2010-01-01') b ON a.paytmmerchantid = b.edc_mid) SELECT * FROM (SELECT A.transactionid, A.txn_amount, A.txn_date, A.paytmmerchantid, A.small_vpa, A.mid_type, 'CCUPI_vpa_mid_hourly_limit' AS rule_name, A.txn_timestamp , COUNT(B.transactionid) as txn1_hr , 3 as txn1_hr_threshold , SUM(B.txn_amount) as amt1_hr , 2000 as amt1_hr_threshold FROM (SELECT * FROM offus_txn WHERE txn_date BETWEEN date '2025-05-01' AND DATE'2025-05-31')A INNER JOIN (SELECT * FROM offus_txn)B ON A.small_vpa = B.small_vpa AND A.paytmmerchantid = B.paytmmerchantid AND (A.txn_timestamp - B.txn_timestamp) BETWEEN 0 AND 3600000 -- <= 1hour AND A.transactionid <> B.transactionid GROUP BY 1,2,3,4,5,6,7,8) WHERE (txn1_hr >= txn1_hr_threshold) AND ((amt1_hr + txn_amount) > amt1_hr_threshold) ;
-- CCUPI_vpa_mid_daily_limit -- DROP TABLE team_kingkong.offus_CCUPI_vpa_mid_daily_limit_breaches; -- CREATE TABLE team_kingkong.offus_CCUPI_vpa_mid_daily_limit_breaches AS INSERT INTO team_kingkong.offus_CCUPI_vpa_mid_daily_limit_breaches with offus_txn as (SELECT transactionid, txn_amount, txn_date, paytmmerchantid, txn_timestamp, small_vpa , case when edc_mid is not null then 'EDC' else 'QR' end as mid_type FROM (SELECT DISTINCT pg_mid from cdo.total_offline_merchant_base_snapshot_v3) f INNER join ( select distinct transactionid , cast(eventamount as double)/100 as txn_amount , paytmmerchantid , DATE(dl_last_updated) AS txn_date , CAST(velocitytimestamp AS DOUBLE) AS txn_timestamp , small_vpa from cdp_risk_transform.maquette_flattened_offus_snapshot_v3 where dl_last_updated BETWEEN DATE(DATE'2025-05-01' - INTERVAL '1' DAY) AND DATE'2025-05-31' -- and paymethod in ('CREDIT_CARD','DEBIT_CARD','EMI','EMI_DC') AND isupicc = 'true' AND actionrecommended <> 'BLOCK') a on a.paytmmerchantid = f.pg_mid LEFT JOIN (SELECT DISTINCT mid AS edc_mid FROM paytmpgdb.entity_edc_info_snapshot_v3 WHERE terminal_status = 'ACTIVE' AND dl_last_updated >= DATE '2010-01-01') b ON a.paytmmerchantid = b.edc_mid) SELECT * FROM (SELECT A.transactionid, A.txn_amount, A.txn_date, A.paytmmerchantid, A.small_vpa, A.mid_type, 'CCUPI_vpa_mid_daily_limit' AS rule_name, A.txn_timestamp , COUNT(B.transactionid) as txn1_day , 5 as txn1_day_threshold FROM (SELECT * FROM offus_txn WHERE txn_date BETWEEN date '2025-05-01' AND DATE'2025-05-31' AND txn_amount <= 2000)A INNER JOIN (SELECT * FROM offus_txn)B ON A.small_vpa = B.small_vpa AND A.paytmmerchantid = B.paytmmerchantid AND (A.txn_timestamp - B.txn_timestamp) BETWEEN 0 AND 3600000 -- <= 1hour AND A.transactionid <> B.transactionid GROUP BY 1,2,3,4,5,6,7,8) WHERE txn1_day >= txn1_day_threshold ;
{ "blocks": [ { "type": "header", "text": { "type": "plain_text", "text": ":aboriginal_flag: Xero Boost Days - What's On :aboriginal_flag:" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "Good Morning Meanjin, and welcome to Reconciliation Week!\n\n *Reconciliation Week (27 May – 3 June)* is a time for all Australians to learn about our shared histories, cultures, and achievements, and to explore how we can contribute to reconciliation in Australia. \n\n For Aboriginal and Torres Strait Islander peoples, it’s a powerful reminder of ongoing resilience, the importance of truth-telling, and the work still needed to achieve genuine equity and justice." } }, { "type": "divider" }, { "type": "header", "text": { "type": "plain_text", "text": ":calendar-date-3: Monday, 26th May", "emoji": true } }, { "type": "section", "text": { "type": "mrkdwn", "text": "\n:coffee: *Café Partnership*: Enjoy free coffee and café-style beverages from our Cafe partner *Edwards*.\n:Lunch: *Lunch*: from *12pm* in the kitchen.\n:massage:*Wellbeing*: Pilates at *SP Brisbane City* is bookable every Monday!" } }, { "type": "header", "text": { "type": "plain_text", "text": ":calendar-date-28: Wednesday, 28th May", "emoji": true } }, { "type": "section", "text": { "type": "mrkdwn", "text": ":coffee: *Café Partnership*: Enjoy free coffee and café-style beverages from our Cafe partner *Edwards*.\n:lunch: *Reconciliation Week Morning Tea* provided by <https://jarrahcatering.com.au/|Jarrah Catering> from *9:30am* in the kitchen! \n\n :microphone: We will also have a video of our very own *Tony Davison* talking on behalf of the #reconciliation-au ERG around Xero's Reconciliation plan and what this week means! \n\n :slack: In the thread we will also have a special background for you to use on Google Meet if you would like to participate." } }, { "type": "header", "text": { "type": "plain_text", "text": ":calendar-date-30: Friday, 30th May", "emoji": true } }, { "type": "section", "text": { "type": "mrkdwn", "text": ":cheers-9743: *Social Happy Hour* from 3pm - 4pm in the kitchen! Wind down for the week over some delicious drinks & nibbles." } }, { "type": "divider" }, { "type": "section", "text": { "type": "mrkdwn", "text": "Stay tuned to this channel for more details, check out the <https://calendar.google.com/calendar/u/0?cid=Y19uY2M4cDN1NDRsdTdhczE0MDhvYjZhNnRjb0Bncm91cC5jYWxlbmRhci5nb29nbGUuY29t|*Brisbane Social Calendar*>, and get ready to Boost your workdays!\n\nLove,\nWX Team :party-wx:" } } ] }
<?php // Exit if accessed directly if ( !defined( 'ABSPATH' ) ) exit; // BEGIN ENQUEUE PARENT ACTION // AUTO GENERATED - Do not modify or remove comment markers above or below: if ( !function_exists( 'chld_thm_cfg_locale_css' ) ): function chld_thm_cfg_locale_css( $uri ){ if ( empty( $uri ) && is_rtl() && file_exists( get_template_directory() . '/rtl.css' ) ) $uri = get_template_directory_uri() . '/rtl.css'; return $uri; } endif; add_filter( 'locale_stylesheet_uri', 'chld_thm_cfg_locale_css' ); if ( !function_exists( 'child_theme_configurator_css' ) ): function child_theme_configurator_css() { wp_enqueue_style( 'chld_thm_cfg_child', trailingslashit( get_stylesheet_directory_uri() ) . 'style.css', array( 'hello-elementor','hello-elementor','hello-elementor-theme-style','hello-elementor-header-footer' ) ); } endif; add_action( 'wp_enqueue_scripts', 'child_theme_configurator_css', 10 ); // END ENQUEUE PARENT ACTION /* Theme Name: Hello Elementor Child Theme URI: https://elementor.com/hello-theme/?utm_source=wp-themes&utm_campaign=theme-uri&utm_medium=wp-dash Template: hello-elementor Author: Elementor Team Author URI: https://elementor.com/?utm_source=wp-themes&utm_campaign=author-uri&utm_medium=wp-dash Description: Hello Elementor is a lightweight and minimalist WordPress theme that was built specifically to work seamlessly with the Elementor site builder plugin. The theme is free, open-source, and designed for users who want a flexible, easy-to-use, and customizable website. The theme, which is optimized for performance, provides a solid foundation for users to build their own unique designs using the Elementor drag-and-drop site builder. Its simplicity and flexibility make it a great choice for both beginners and experienced Web Creators. Tags: accessibility-ready,flexible-header,custom-colors,custom-menu,custom-logo,featured-images,rtl-language-support,threaded-comments,translation-ready Version: 3.3.0.1744009168 Updated: 2025-04-07 06:59:28 */
<?php // Exit if accessed directly if ( !defined( 'ABSPATH' ) ) exit; // BEGIN ENQUEUE PARENT ACTION // AUTO GENERATED - Do not modify or remove comment markers above or below: if ( !function_exists( 'chld_thm_cfg_locale_css' ) ): function chld_thm_cfg_locale_css( $uri ){ if ( empty( $uri ) && is_rtl() && file_exists( get_template_directory() . '/rtl.css' ) ) $uri = get_template_directory_uri() . '/rtl.css'; return $uri; } endif; add_filter( 'locale_stylesheet_uri', 'chld_thm_cfg_locale_css' ); if ( !function_exists( 'child_theme_configurator_css' ) ): function child_theme_configurator_css() { wp_enqueue_style( 'chld_thm_cfg_child', trailingslashit( get_stylesheet_directory_uri() ) . 'style.css', array( 'hello-elementor','hello-elementor','hello-elementor-theme-style','hello-elementor-header-footer' ) ); } endif; add_action( 'wp_enqueue_scripts', 'child_theme_configurator_css', 10 ); // END ENQUEUE PARENT ACTION /* Theme Name: Hello Elementor Child Theme URI: https://elementor.com/hello-theme/?utm_source=wp-themes&utm_campaign=theme-uri&utm_medium=wp-dash Template: hello-elementor Author: Elementor Team Author URI: https://elementor.com/?utm_source=wp-themes&utm_campaign=author-uri&utm_medium=wp-dash Description: Hello Elementor is a lightweight and minimalist WordPress theme that was built specifically to work seamlessly with the Elementor site builder plugin. The theme is free, open-source, and designed for users who want a flexible, easy-to-use, and customizable website. The theme, which is optimized for performance, provides a solid foundation for users to build their own unique designs using the Elementor drag-and-drop site builder. Its simplicity and flexibility make it a great choice for both beginners and experienced Web Creators. Tags: accessibility-ready,flexible-header,custom-colors,custom-menu,custom-logo,featured-images,rtl-language-support,threaded-comments,translation-ready Version: 3.3.0.1744009168 Updated: 2025-04-07 06:59:28 */
-- MONTHLY BREACH COUNT -- team_kingkong.offus_MID_CCDC_Daily_TXN_limit_Check_breaches SELECT substr(cast(txn_date as varchar(30)), 1, 7) as year_month , COUNT(transactionid) AS breach_cnt , SUM(txn_amount) as breach_amt , COUNT(DISTINCT globalcardindex) as card_cnt FROM (SELECT DISTINCT * FROM team_kingkong.offus_MID_CCDC_Daily_TXN_limit_Check_breaches) GROUP BY 1 ORDER BY 1; -- team_kingkong.offus_edc_card_velocity_count_breaches SELECT substr(cast(txn_date as varchar(30)), 1, 7) as year_month , COUNT(transactionid) AS breach_cnt , SUM(txn_amount) as breach_amt , COUNT(DISTINCT globalcardindex) as card_cnt FROM (SELECT DISTINCT * FROM team_kingkong.offus_edc_card_velocity_count_breaches) GROUP BY 1 ORDER BY 1; -- team_kingkong.offus_Merchant_PerTxnLimit_Check_breaches SELECT substr(cast(txn_date as varchar(30)), 1, 7) as year_month , COUNT(transactionid) AS breach_cnt , SUM(txn_amount) as breach_amt -- , COUNT(DISTINCT globalcardindex) as card_cnt FROM (SELECT DISTINCT * FROM team_kingkong.offus_Merchant_PerTxnLimit_Check_breaches) GROUP BY 1 ORDER BY 1; -- team_kingkong.offus_edc_card_velocity_amount_breaches SELECT substr(cast(txn_date as varchar(30)), 1, 7) as year_month , COUNT(transactionid) AS breach_cnt , SUM(txn_amount) as breach_amt , COUNT(DISTINCT globalcardindex) as card_cnt FROM (SELECT DISTINCT * FROM team_kingkong.offus_edc_card_velocity_amount_breaches) GROUP BY 1 ORDER BY 1; -- team_kingkong.offus_MID_UPI_Daily_TXN_limit_Check_breaches SELECT substr(cast(txn_date as varchar(30)), 1, 7) as year_month , COUNT(transactionid) AS breach_cnt , SUM(txn_amount) as breach_amt , COUNT(DISTINCT globalcardindex) as card_cnt FROM (SELECT DISTINCT * FROM team_kingkong.offus_MID_UPI_Daily_TXN_limit_Check_breaches) GROUP BY 1 ORDER BY 1; -- team_kingkong.offus_oil_gas_dc_limit_EDC_breaches SELECT substr(cast(txn_date as varchar(30)), 1, 7) as year_month , COUNT(transactionid) AS breach_cnt , SUM(txn_amount) as breach_amt , COUNT(DISTINCT globalcardindex) as card_cnt FROM (SELECT DISTINCT * FROM team_kingkong.offus_oil_gas_dc_limit_EDC_breaches) GROUP BY 1 ORDER BY 1; -- team_kingkong.offus_ICA_Unsafe_Country_Transactions_breaches SELECT substr(cast(txn_date as varchar(30)), 1, 7) as year_month , COUNT(transactionid) AS breach_cnt , SUM(txn_amount) as breach_amt , COUNT(DISTINCT globalcardindex) as card_cnt FROM (SELECT DISTINCT * FROM team_kingkong.offus_ICA_Unsafe_Country_Transactions_breaches) GROUP BY 1 ORDER BY 1;
-- RECHCECKING -- OFFUS : edc_card_velocity_amount -- edc_card_velocity_amount -- DROP TABLE IF EXISTS team_kingkong.offus_edc_card_velocity_amount_breaches2; -- DROP TABLE IF EXISTS team_kingkong.offus_edc_card_velocity_amount_breaches; -- CREATE TABLE team_kingkong.offus_edc_card_velocity_amount_breaches AS INSERT INTO team_kingkong.offus_edc_card_velocity_amount_breaches with offus_txn as (SELECT DISTINCT globalcardindex, transactionid, txn_amount, txn_date, paytmmerchantid, txn_timestamp FROM (SELECT DISTINCT pg_mid from cdo.total_offline_merchant_base_snapshot_v3) f INNER join (select transactionid , cast(eventamount as double)/100 as txn_amount , paytmmerchantid , globalcardindex , DATE(dl_last_updated) AS txn_date , CAST(velocitytimestamp AS DOUBLE) AS txn_timestamp from cdp_risk_transform.maquette_flattened_offus_snapshot_v3 where dl_last_updated BETWEEN date'2025-05-01' AND DATE'2025-05-31' and paymethod in ('CREDIT_CARD','DEBIT_CARD','EMI','EMI_DC') AND actionrecommended <> 'BLOCK' AND responsestatus = 'SUCCESS' AND paytmmerchantid IS NOT NULL AND paytmmerchantid <> '' AND paytmmerchantid <> ' ' AND globalcardindex IS NOT NULL AND globalcardindex <> '' AND globalcardindex <> ' ') a on a.paytmmerchantid = f.pg_mid LEFT JOIN (SELECT mid AS edc_mid FROM paytmpgdb.entity_edc_info_snapshot_v3 WHERE terminal_status = 'ACTIVE' AND dl_last_updated >= DATE '2010-01-01') b ON a.paytmmerchantid = b.edc_mid) SELECT * FROM (SELECT A.globalcardindex, A.transactionid, A.txn_amount, A.txn_date, A.paytmmerchantid, 'edc_card_velocity_amount' AS rule_name, A.txn_timestamp , SUM(IF((A.txn_timestamp - B.txn_timestamp) BETWEEN 0 AND 21600000, B.txn_amount, NULL)) AS amt6_hr , 1000000 AS amt6_hr_threshold , SUM(B.txn_amount) as amt24_hr , 2000000 AS amt4_hr_threshold FROM (SELECT * FROM offus_txn WHERE txn_date BETWEEN date'2025-05-01' AND DATE'2025-05-31')A INNER JOIN (SELECT * FROM offus_txn)B ON A.globalcardindex = b.globalcardindex AND A.paytmmerchantid = B.paytmmerchantid AND A.transactionid <> B.transactionid AND (A.txn_timestamp - B.txn_timestamp) BETWEEN 0 AND 86400000 -- <= 1d GROUP BY 1,2,3,4,5,6,7) WHERE ((amt6_hr + txn_amount) > 1000000) OR ((amt24_hr + txn_amount) > 2000000);
Tue May 27 2025 05:51:09 GMT+0000 (Coordinated Universal Time) https://kanhasoft.com/custom-amazon-seller-tools.html
@kanhasoft #amazonsellers tools #customamazon sellers tools #sellerstools
Tue May 27 2025 05:48:53 GMT+0000 (Coordinated Universal Time) https://kanhasoft.com/mobile-app-development.html
@kanhasoft #mobileapplication development #mobileapplication #appdevelopment #ai-poweredapplications
Tue May 27 2025 05:45:04 GMT+0000 (Coordinated Universal Time) https://kanhasoft.com/web-app-development.html
Mon May 26 2025 20:36:58 GMT+0000 (Coordinated Universal Time) https://www.linuxuntu.com/install-safari-linux/
Mon May 26 2025 20:32:51 GMT+0000 (Coordinated Universal Time) https://www.linuxuntu.com/install-safari-linux/
Mon May 26 2025 10:31:13 GMT+0000 (Coordinated Universal Time) https://www.coinsclone.com/otc-trading-platform-development/
@CharleenStewar #otctradingplatform #otc trading platform development
Mon May 26 2025 10:23:30 GMT+0000 (Coordinated Universal Time) https://maticz.com/ico-development
Mon May 26 2025 01:46:04 GMT+0000 (Coordinated Universal Time) https://filebrowser.org/installation
Mon May 26 2025 01:41:17 GMT+0000 (Coordinated Universal Time) https://launchpad.net/~christian-boxdoerfer/+archive/ubuntu/fsearch-stable
Sun May 25 2025 08:07:11 GMT+0000 (Coordinated Universal Time) https://github.com/theapache64/SoundCloud-Downloader
Sat May 24 2025 11:27:44 GMT+0000 (Coordinated Universal Time) https://www.firekirin.xyz:8888/Store.aspx
Sat May 24 2025 10:35:25 GMT+0000 (Coordinated Universal Time) https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Structuring_content/Webpage_metadata
Sat May 24 2025 06:44:32 GMT+0000 (Coordinated Universal Time) https://www.beleaftechnologies.com/crypto-algo-trading-bot-development
Fri May 23 2025 11:03:10 GMT+0000 (Coordinated Universal Time) https://www.hivelance.com/coinbase-clone-script
Thu May 22 2025 14:33:37 GMT+0000 (Coordinated Universal Time) https://www.techigator.ae/services/logo-design-dubai