Project: RR Shop 12Mar26 Last Working Codes ZIP File: Relevant Reflex Shop.zip Extracted on: 2026-03-12 08:35:45 Total Files: 44 ================================================================================ FILE: Relevant Reflex Shop/admin-invoice-pdf.php TYPE: PHP SIZE: 13.48 KB ------------------------------------------------------------ prepare(" SELECT i.*, p.project_name, p.eloi, p.sample_size, p.industry, p.closed_at FROM invoices i INNER JOIN projects p ON i.project_id = p.id WHERE i.id = ? "); $stmt->execute([$invoiceId]); $inv = $stmt->fetch(PDO::FETCH_ASSOC); if (!$inv) { header('Location: finance.php'); exit; } // Load company settings for bank details & footer $settings = []; try { $result = $pdo->query("SELECT setting_key, setting_value FROM company_settings"); while ($row = $result->fetch()) $settings[$row['setting_key']] = $row['setting_value']; } catch (Exception $e) {} $sym = $inv['currency_symbol'] ?? '₹'; $currLabel = ['INR'=>'Indian Rupees','USD'=>'US Dollars','EUR'=>'Euros'][$inv['currency']] ?? $inv['currency']; ?>
☎
✉
🌐
| # | Description | Qty | Rate | Amount |
|---|---|---|---|---|
| 1 | Sample Cost Online survey fielding & data collection (Avg LOI: min) |
completes | ||
| 2 | Respondent Incentive Panel member incentive payments |
completes |
Update affiliate information for
Complete information for
No signups yet
| Clicked At | Signed Up | Verified | Reward | Status | |
|---|---|---|---|---|---|
| Not completed'; ?> | ✅ Pending | ✅ Not verified | ₹ Pending | Complete Awaiting Verification Clicked Only |
View and manage client information
No documents uploaded yet
Manage client accounts and projects
| ID | Client Code | Company Name | Industry | Contact Person | Location | Email & Phone | Projects | Revenue | Status | Actions |
|---|---|---|---|---|---|---|---|---|---|---|
| No clients found. Click "Add New Client" to create one. | ||||||||||
| # |
|
₹ | ||||||||
Market insights and demand forecasting for strategic decisions
Recommended Action:
Our technical team is available 24/7 to help resolve system issues.
Manage pricing, invoices & financial settings
Test your pricing by entering an LOI. Uses the saved rates above and live exchange rates.
No invoices found. Invoices are auto-generated when projects are closed.
| Invoice # | Client | Project | Curr | N | Total | Invoiced | Due | Status | Actions |
|---|---|---|---|---|---|---|---|---|---|
| 📄 |
* All amounts are inclusive of applicable taxes
-------------------- END OF FILE -------------------- FILE: Relevant Reflex Shop/generate_hash.php TYPE: PHP SIZE: 184 B ------------------------------------------------------------ php -------------------- END OF FILE -------------------- FILE: Relevant Reflex Shop/generate_panelbook.py TYPE: PY SIZE: 27.41 KB ------------------------------------------------------------ #!/usr/bin/env python3 """ Relevant Reflex — Panel Book PDF Generator Reads JSON data, produces a branded PDF with charts. Usage: python3 generate_panelbook.py input.json output.pdf """ import sys, json, io, math from datetime import datetime import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import matplotlib.ticker as mticker from reportlab.lib.pagesizes import A4 from reportlab.lib.units import mm, cm from reportlab.lib.colors import HexColor, white, black from reportlab.lib.styles import ParagraphStyle from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT from reportlab.platypus import ( SimpleDocTemplate, Paragraph, Spacer, Image, PageBreak, Table, TableStyle, KeepTogether ) from reportlab.lib import colors from reportlab.pdfgen import canvas # ─── Brand Palette ─── RR_GREEN = HexColor('#059669') RR_DARK = HexColor('#064e3b') RR_LIGHT = HexColor('#ecfdf5') SLATE_900 = HexColor('#0f172a') SLATE_700 = HexColor('#334155') SLATE_500 = HexColor('#64748b') SLATE_300 = HexColor('#cbd5e1') SLATE_100 = HexColor('#f1f5f9') SLATE_50 = HexColor('#f8fafc') WHITE = white # Chart color palette (muted, professional) CHART_COLORS = [ '#059669', '#0d9488', '#0891b2', '#0284c7', '#4f46e5', '#7c3aed', '#c026d3', '#e11d48', '#ea580c', '#d97706', '#65a30d', '#16a34a', '#94a3b8', '#64748b', '#475569', '#334155' ] W, H = A4 # 595.27, 841.89 # ────────────────────────────────────────────── # Chart Generators (return PNG bytes via BytesIO) # ────────────────────────────────────────────── def _apply_style(): plt.rcParams.update({ 'font.family': 'sans-serif', 'font.sans-serif': ['Helvetica', 'Arial', 'DejaVu Sans'], 'font.size': 8, 'axes.labelsize': 8, 'axes.titlesize': 9, 'xtick.labelsize': 7, 'ytick.labelsize': 7, 'figure.facecolor': 'white', 'axes.facecolor': 'white', 'axes.edgecolor': '#cbd5e1', 'axes.grid': False, 'axes.spines.top': False, 'axes.spines.right': False, }) def make_pie_chart(labels, values, title='', w_inch=3.8, h_inch=2.8): _apply_style() fig, ax = plt.subplots(figsize=(w_inch, h_inch)) clrs = CHART_COLORS[:len(labels)] wedges, texts, autotexts = ax.pie( values, labels=None, autopct='%1.1f%%', startangle=140, colors=clrs, pctdistance=0.75, wedgeprops=dict(width=0.5, edgecolor='white', linewidth=2) ) for t in autotexts: t.set_fontsize(7) t.set_color('#334155') t.set_fontweight('bold') ax.legend( [f'{l} ({v:,})' for l, v in zip(labels, values)], loc='center left', bbox_to_anchor=(1, 0.5), fontsize=7, frameon=False, labelspacing=0.8 ) if title: ax.set_title(title, fontsize=9, fontweight='bold', color='#0f172a', pad=8) fig.tight_layout(pad=0.5) buf = io.BytesIO() fig.savefig(buf, format='png', dpi=180, bbox_inches='tight', facecolor='white') plt.close(fig) buf.seek(0) return buf def make_hbar_chart(labels, values, title='', w_inch=5.2, h_inch=None, color='#059669'): _apply_style() n = len(labels) if h_inch is None: h_inch = max(1.6, min(n * 0.32 + 0.6, 7.5)) fig, ax = plt.subplots(figsize=(w_inch, h_inch)) # Truncate long labels short_labels = [l[:35] + '...' if len(str(l)) > 35 else str(l) for l in labels] y_pos = range(n) bars = ax.barh(y_pos, values, color=color, height=0.65, edgecolor='white', linewidth=0.5) ax.set_yticks(y_pos) ax.set_yticklabels(short_labels, fontsize=7, color='#334155') ax.invert_yaxis() ax.set_xlabel('') # Value labels on bars max_val = max(values) if values else 1 for bar, val in zip(bars, values): pct_of_total = (val / sum(values) * 100) if sum(values) > 0 else 0 ax.text(bar.get_width() + max_val * 0.02, bar.get_y() + bar.get_height()/2, f'{val:,} ({pct_of_total:.1f}%)', va='center', fontsize=6.5, color='#64748b') ax.set_xlim(0, max_val * 1.35) ax.xaxis.set_major_formatter(mticker.FuncFormatter(lambda x, _: f'{int(x):,}')) if title: ax.set_title(title, fontsize=9, fontweight='bold', color='#0f172a', pad=8, loc='left') ax.spines['left'].set_color('#e2e8f0') ax.spines['bottom'].set_color('#e2e8f0') ax.tick_params(axis='x', colors='#94a3b8') fig.tight_layout(pad=0.5) buf = io.BytesIO() fig.savefig(buf, format='png', dpi=180, bbox_inches='tight', facecolor='white') plt.close(fig) buf.seek(0) return buf def make_vbar_chart(labels, values, title='', w_inch=5.2, h_inch=2.5, color='#059669'): _apply_style() fig, ax = plt.subplots(figsize=(w_inch, h_inch)) x_pos = range(len(labels)) bars = ax.bar(x_pos, values, color=color, width=0.6, edgecolor='white', linewidth=0.5) ax.set_xticks(x_pos) ax.set_xticklabels(labels, fontsize=7, color='#334155', rotation=0) ax.set_ylabel('') for bar, val in zip(bars, values): ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + max(values)*0.02, f'{val:,}', ha='center', va='bottom', fontsize=7, color='#334155', fontweight='bold') ax.set_ylim(0, max(values) * 1.2 if values else 1) ax.yaxis.set_major_formatter(mticker.FuncFormatter(lambda x, _: f'{int(x):,}')) if title: ax.set_title(title, fontsize=9, fontweight='bold', color='#0f172a', pad=8, loc='left') ax.spines['left'].set_color('#e2e8f0') ax.spines['bottom'].set_color('#e2e8f0') ax.tick_params(axis='y', colors='#94a3b8') fig.tight_layout(pad=0.5) buf = io.BytesIO() fig.savefig(buf, format='png', dpi=180, bbox_inches='tight', facecolor='white') plt.close(fig) buf.seek(0) return buf # ────────────────────────────────────────────── # Custom Page Template (header/footer) # ────────────────────────────────────────────── class PanelBookTemplate(SimpleDocTemplate): def __init__(self, *args, **kwargs): self.page_count = 0 self.is_cover = True super().__init__(*args, **kwargs) def afterPage(self): self.page_count += 1 def draw_page(canvas_obj, doc): """Draw header line and footer on every page except cover.""" canvas_obj.saveState() if doc.page_count == 0: # Cover page — no header/footer canvas_obj.restoreState() return page_num = doc.page_count + 1 # Top line canvas_obj.setStrokeColor(RR_GREEN) canvas_obj.setLineWidth(1.5) canvas_obj.line(30, H - 28, W - 30, H - 28) # Header text canvas_obj.setFont('Helvetica-Bold', 7) canvas_obj.setFillColor(SLATE_500) canvas_obj.drawString(32, H - 24, 'RELEVANT REFLEX') canvas_obj.setFont('Helvetica', 7) canvas_obj.drawRightString(W - 32, H - 24, 'Panel Book') # Footer canvas_obj.setStrokeColor(SLATE_300) canvas_obj.setLineWidth(0.5) canvas_obj.line(30, 32, W - 30, 32) canvas_obj.setFont('Helvetica', 6.5) canvas_obj.setFillColor(SLATE_500) canvas_obj.drawString(32, 20, 'Confidential — Relevant Reflex Panel Book') canvas_obj.drawRightString(W - 32, 20, f'Page {page_num}') canvas_obj.restoreState() # ────────────────────────────────────────────── # Styles # ────────────────────────────────────────────── def get_styles(): return { 'section_title': ParagraphStyle( 'SectionTitle', fontName='Helvetica-Bold', fontSize=16, textColor=SLATE_900, spaceAfter=4, leading=20 ), 'section_sub': ParagraphStyle( 'SectionSub', fontName='Helvetica', fontSize=8.5, textColor=SLATE_500, spaceAfter=16, leading=12 ), 'heading2': ParagraphStyle( 'Heading2', fontName='Helvetica-Bold', fontSize=11, textColor=RR_DARK, spaceAfter=6, spaceBefore=14, leading=14 ), 'body': ParagraphStyle( 'Body', fontName='Helvetica', fontSize=8.5, textColor=SLATE_700, spaceAfter=6, leading=12 ), 'body_center': ParagraphStyle( 'BodyCenter', fontName='Helvetica', fontSize=8.5, textColor=SLATE_700, spaceAfter=6, leading=12, alignment=TA_CENTER ), 'small': ParagraphStyle( 'Small', fontName='Helvetica', fontSize=7, textColor=SLATE_500, spaceAfter=4, leading=10 ), 'small_center': ParagraphStyle( 'SmallCenter', fontName='Helvetica', fontSize=7, textColor=SLATE_500, spaceAfter=4, leading=10, alignment=TA_CENTER ), 'metric_value': ParagraphStyle( 'MetricValue', fontName='Helvetica-Bold', fontSize=22, textColor=RR_GREEN, alignment=TA_CENTER, spaceAfter=0, leading=26 ), 'metric_label': ParagraphStyle( 'MetricLabel', fontName='Helvetica', fontSize=7.5, textColor=SLATE_500, alignment=TA_CENTER, spaceAfter=0, leading=10 ), 'question_title': ParagraphStyle( 'QuestionTitle', fontName='Helvetica-Bold', fontSize=9, textColor=SLATE_900, spaceAfter=2, spaceBefore=6, leading=12 ), 'question_sub': ParagraphStyle( 'QuestionSub', fontName='Helvetica', fontSize=7, textColor=SLATE_500, spaceAfter=6, leading=10 ), } def format_question(qid): """Convert question_id like 'education_level' to 'Education Level'.""" return qid.replace('_', ' ').title() # ────────────────────────────────────────────── # Build PDF # ────────────────────────────────────────────── def build_pdf(data, output_path): doc = PanelBookTemplate( output_path, pagesize=A4, topMargin=38, bottomMargin=44, leftMargin=32, rightMargin=32, title='Relevant Reflex Panel Book', author='Relevant Reflex' ) styles = get_styles() story = [] content_width = W - 64 # left + right margins # ════════════════════════════════════════════ # PAGE 1: COVER # ════════════════════════════════════════════ story.append(Spacer(1, 120)) # Logo block logo_data = [ [Paragraph('RR', ParagraphStyle('Logo', alignment=TA_CENTER))] ] logo_table = Table(logo_data, colWidths=[80], rowHeights=[64]) logo_table.setStyle(TableStyle([ ('BACKGROUND', (0,0), (-1,-1), RR_GREEN), ('ALIGN', (0,0), (-1,-1), 'CENTER'), ('VALIGN', (0,0), (-1,-1), 'MIDDLE'), ('ROUNDEDCORNERS', [12, 12, 12, 12]), ])) # Wrap logo in centered table logo_wrapper = Table([[logo_table]], colWidths=[content_width]) logo_wrapper.setStyle(TableStyle([('ALIGN', (0,0), (-1,-1), 'CENTER')])) story.append(logo_wrapper) story.append(Spacer(1, 24)) # Title story.append(Paragraph('Relevant Reflex', ParagraphStyle( 'CoverBrand', fontName='Helvetica-Bold', fontSize=32, textColor=RR_DARK, alignment=TA_CENTER, leading=38 ))) story.append(Spacer(1, 4)) story.append(Paragraph('Panel Book', ParagraphStyle( 'CoverTitle', fontName='Helvetica', fontSize=24, textColor=SLATE_500, alignment=TA_CENTER, leading=30 ))) story.append(Spacer(1, 10)) # Green divider divider_data = [[' ']] divider = Table(divider_data, colWidths=[80], rowHeights=[3]) divider.setStyle(TableStyle([ ('BACKGROUND', (0,0), (-1,-1), RR_GREEN), ('ROUNDEDCORNERS', [2, 2, 2, 2]), ])) div_wrapper = Table([[divider]], colWidths=[content_width]) div_wrapper.setStyle(TableStyle([('ALIGN', (0,0), (-1,-1), 'CENTER')])) story.append(div_wrapper) story.append(Spacer(1, 20)) # Generation info story.append(Paragraph( f'Generated on {data.get("generated_at", "")}', ParagraphStyle('CoverDate', fontName='Helvetica', fontSize=10, textColor=SLATE_700, alignment=TA_CENTER, leading=14) )) story.append(Spacer(1, 60)) # Disclaimer box disclaimer_text = ( 'All the data in this panel book are 100% based on the actual counts of the panel ' 'and not added/edited by human. This is a real-time snapshot generated at the ' 'date and time mentioned above.' ) disc_data = [[Paragraph(disclaimer_text, ParagraphStyle( 'Disclaimer', fontName='Helvetica', fontSize=7.5, textColor=SLATE_700, alignment=TA_CENTER, leading=11 ))]] disc_table = Table(disc_data, colWidths=[content_width * 0.75]) disc_table.setStyle(TableStyle([ ('BACKGROUND', (0,0), (-1,-1), SLATE_50), ('BOX', (0,0), (-1,-1), 0.5, SLATE_300), ('TOPPADDING', (0,0), (-1,-1), 12), ('BOTTOMPADDING', (0,0), (-1,-1), 12), ('LEFTPADDING', (0,0), (-1,-1), 16), ('RIGHTPADDING', (0,0), (-1,-1), 16), ])) disc_wrapper = Table([[disc_table]], colWidths=[content_width]) disc_wrapper.setStyle(TableStyle([('ALIGN', (0,0), (-1,-1), 'CENTER')])) story.append(disc_wrapper) story.append(Spacer(1, 80)) # Footer note on cover story.append(Paragraph( 'www.relevantreflex.com', ParagraphStyle('CoverURL', fontName='Helvetica', fontSize=8, textColor=SLATE_500, alignment=TA_CENTER) )) story.append(PageBreak()) # ════════════════════════════════════════════ # PAGE 2: PANEL QUALITY OVERVIEW # ════════════════════════════════════════════ story.append(Paragraph('Panel Overview', styles['section_title'])) story.append(Paragraph('Key quality metrics and panel health indicators.', styles['section_sub'])) # Metrics grid (2 rows x 3 cols) verified = data.get('verified_members', 0) active = data.get('active_members', 0) total = data.get('total_members', 0) quality = data.get('quality', {}) def metric_cell(value, label): return [ Paragraph(str(value), styles['metric_value']), Paragraph(label, styles['metric_label']) ] metrics_data = [ [ metric_cell(f'{total:,}', 'Total Registered'), metric_cell(f'{active:,}', 'Active Members'), metric_cell(f'{verified:,}', 'Email Verified'), ], [ metric_cell(f'{quality.get("members_with_profiler", 0):,}', 'Profiler Completed'), metric_cell(f'{quality.get("mobile_verified", 0):,}', 'Mobile Verified'), metric_cell(f'{quality.get("avg_profiler_completion", 0):.0f}%', 'Avg. Profiler Completion'), ] ] # Flatten for Table (each metric_cell is a list of 2 paragraphs, put in inner table) def metric_inner(val_label_pair): t = Table([val_label_pair], colWidths=[content_width/3 - 12]) t.setStyle(TableStyle([ ('ALIGN', (0,0), (-1,-1), 'CENTER'), ('VALIGN', (0,0), (-1,-1), 'MIDDLE'), ('TOPPADDING', (0,0), (-1,-1), 14), ('BOTTOMPADDING', (0,0), (-1,-1), 14), ])) return t row1 = [metric_inner(m) for m in metrics_data[0]] row2 = [metric_inner(m) for m in metrics_data[1]] col_w = content_width / 3 metrics_table = Table([row1, row2], colWidths=[col_w]*3, rowHeights=[72, 72]) metrics_table.setStyle(TableStyle([ ('GRID', (0,0), (-1,-1), 0.5, SLATE_300), ('BACKGROUND', (0,0), (-1,-1), SLATE_50), ('ALIGN', (0,0), (-1,-1), 'CENTER'), ('VALIGN', (0,0), (-1,-1), 'MIDDLE'), ('ROUNDEDCORNERS', [8, 8, 8, 8]), ])) story.append(metrics_table) story.append(Spacer(1, 20)) # Project Stats if quality.get('total_projects', 0) > 0: story.append(Paragraph('Research Activity', styles['heading2'])) proj_data = [ ['Total Projects', 'Invitations Sent', 'Completed Surveys'], [ Paragraph(f'{quality.get("total_projects", 0):,}', styles['body_center']), Paragraph(f'{quality.get("total_surveys_sent", 0):,}', styles['body_center']), Paragraph(f'{quality.get("total_completes", 0):,}', styles['body_center']), ] ] proj_table = Table(proj_data, colWidths=[col_w]*3) proj_table.setStyle(TableStyle([ ('BACKGROUND', (0,0), (-1,0), RR_DARK), ('TEXTCOLOR', (0,0), (-1,0), WHITE), ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'), ('FONTSIZE', (0,0), (-1,0), 7.5), ('ALIGN', (0,0), (-1,-1), 'CENTER'), ('VALIGN', (0,0), (-1,-1), 'MIDDLE'), ('GRID', (0,0), (-1,-1), 0.5, SLATE_300), ('TOPPADDING', (0,0), (-1,-1), 8), ('BOTTOMPADDING', (0,0), (-1,-1), 8), ])) story.append(proj_table) # Profiler completion rates story.append(Spacer(1, 18)) story.append(Paragraph('Profiler Completion Rates', styles['heading2'])) prof_comp = data.get('profiler_completion', {}) prof_sections = data.get('profiler_sections', {}) comp_header = ['Section', 'Started', 'Completed'] comp_rows = [comp_header] for key, label in prof_sections.items(): pc = prof_comp.get(key, {}) comp_rows.append([ label, f'{pc.get("started", 0):,}', f'{pc.get("completed", 0):,}' ]) comp_table = Table(comp_rows, colWidths=[content_width * 0.55, content_width * 0.225, content_width * 0.225]) comp_table.setStyle(TableStyle([ ('BACKGROUND', (0,0), (-1,0), RR_DARK), ('TEXTCOLOR', (0,0), (-1,0), WHITE), ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'), ('FONTSIZE', (0,0), (-1,-1), 7.5), ('FONTNAME', (0,1), (-1,-1), 'Helvetica'), ('ALIGN', (1,0), (-1,-1), 'CENTER'), ('VALIGN', (0,0), (-1,-1), 'MIDDLE'), ('GRID', (0,0), (-1,-1), 0.5, SLATE_300), ('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, SLATE_50]), ('TOPPADDING', (0,0), (-1,-1), 6), ('BOTTOMPADDING', (0,0), (-1,-1), 6), ('LEFTPADDING', (0,0), (0,-1), 10), ])) story.append(comp_table) story.append(PageBreak()) # ════════════════════════════════════════════ # PAGE 3: DEMOGRAPHICS # ════════════════════════════════════════════ story.append(Paragraph('Demographics', styles['section_title'])) story.append(Paragraph( f'Distribution of {verified:,} active, verified panel members.', styles['section_sub'] )) # Gender Pie gender_data = data.get('gender', []) if gender_data: labels = [g['gender'] or 'Not Specified' for g in gender_data] values = [g['count'] for g in gender_data] buf = make_pie_chart(labels, values, 'Gender Distribution') img = Image(buf, width=content_width * 0.75, height=content_width * 0.55) story.append(img) story.append(Spacer(1, 12)) # Age Bar age_data = data.get('age', []) if age_data: labels = [a['age_group'] for a in age_data] values = [a['count'] for a in age_data] buf = make_vbar_chart(labels, values, 'Age Distribution', w_inch=5.2, h_inch=2.5, color='#059669') img = Image(buf, width=content_width, height=content_width * 0.48) story.append(img) story.append(Spacer(1, 12)) # Geography Bar geo_data = data.get('geography', []) if geo_data: story.append(PageBreak()) story.append(Paragraph('Geographic Distribution', styles['section_title'])) story.append(Paragraph('Top 20 postcode regions by panel size.', styles['section_sub'])) labels = [g['region'] for g in geo_data] values = [g['count'] for g in geo_data] buf = make_hbar_chart(labels, values, 'Members by Postcode Prefix (Top 20)', color='#0d9488') h_ratio = max(1.6, min(len(labels) * 0.32 + 0.6, 7.5)) / 5.2 img = Image(buf, width=content_width, height=content_width * h_ratio) story.append(img) story.append(PageBreak()) # ════════════════════════════════════════════ # PAGES 4+: PROFILER SECTIONS # ════════════════════════════════════════════ profiler_data = data.get('profiler_data', {}) section_colors = list(CHART_COLORS) for sec_idx, (sec_key, sec_label) in enumerate(prof_sections.items()): if sec_key not in profiler_data: continue questions = profiler_data[sec_key] if not questions: continue sec_color = section_colors[sec_idx % len(section_colors)] # Section header story.append(Paragraph(sec_label, styles['section_title'])) pc = prof_comp.get(sec_key, {}) story.append(Paragraph( f'{len(questions)} question{"s" if len(questions) != 1 else ""} — ' f'{pc.get("completed", 0):,} members completed this section.', styles['section_sub'] )) for q_idx, (qid, qdata) in enumerate(questions.items()): dist = qdata.get('distribution', []) resp_count = qdata.get('respondent_count', 0) if not dist: continue labels = [d['label'] for d in dist] values = [d['count'] for d in dist] q_title = format_question(qid) # Decide chart type n_cats = len(dist) elements = [] elements.append(Paragraph(q_title, styles['question_title'])) elements.append(Paragraph( f'{resp_count:,} respondents', styles['question_sub'] )) if n_cats <= 5 and n_cats >= 2: # Pie chart for small category counts buf = make_pie_chart(labels, values, '', w_inch=3.8, h_inch=2.2) img = Image(buf, width=content_width * 0.72, height=content_width * 0.42) else: # Horizontal bar for larger category counts buf = make_hbar_chart(labels, values, '', color=sec_color) n = len(labels) h_ratio = max(1.4, min(n * 0.3 + 0.5, 6.5)) / 5.2 img = Image(buf, width=content_width * 0.92, height=content_width * h_ratio * 0.92) elements.append(img) elements.append(Spacer(1, 10)) # Try to keep question + chart together story.append(KeepTogether(elements)) story.append(PageBreak()) # ════════════════════════════════════════════ # LAST PAGE: CONTACT # ════════════════════════════════════════════ story.append(Spacer(1, 140)) # Logo contact_logo = [[Paragraph('RR', ParagraphStyle('CL', alignment=TA_CENTER))]] cl_table = Table(contact_logo, colWidths=[60], rowHeights=[48]) cl_table.setStyle(TableStyle([ ('BACKGROUND', (0,0), (-1,-1), RR_GREEN), ('ALIGN', (0,0), (-1,-1), 'CENTER'), ('VALIGN', (0,0), (-1,-1), 'MIDDLE'), ('ROUNDEDCORNERS', [10, 10, 10, 10]), ])) cl_wrapper = Table([[cl_table]], colWidths=[content_width]) cl_wrapper.setStyle(TableStyle([('ALIGN', (0,0), (-1,-1), 'CENTER')])) story.append(cl_wrapper) story.append(Spacer(1, 16)) story.append(Paragraph('Relevant Reflex', ParagraphStyle( 'ContactBrand', fontName='Helvetica-Bold', fontSize=20, textColor=RR_DARK, alignment=TA_CENTER, leading=24 ))) story.append(Spacer(1, 4)) story.append(Paragraph("India's Premier Online Research Panel", ParagraphStyle( 'ContactTag', fontName='Helvetica', fontSize=9, textColor=SLATE_500, alignment=TA_CENTER, leading=13 ))) story.append(Spacer(1, 30)) # Contact details contact_items = [ ('Email', 'contact@relevantreflex.com'), ('Support', 'support@relevantreflex.com'), ('Web', 'www.relevantreflex.com'), ('Client Portal', 'www.relevantreflex.com/clients'), ('Location', 'Tamilnadu, India'), ] for label, value in contact_items: story.append(Paragraph( f'{label} ' f'{value}', ParagraphStyle('ContactItem', fontName='Helvetica', fontSize=8.5, alignment=TA_CENTER, leading=18, textColor=SLATE_700) )) story.append(Spacer(1, 40)) # Divider div2 = Table([[' ']], colWidths=[60], rowHeights=[2]) div2.setStyle(TableStyle([('BACKGROUND', (0,0), (-1,-1), SLATE_300)])) div2_w = Table([[div2]], colWidths=[content_width]) div2_w.setStyle(TableStyle([('ALIGN', (0,0), (-1,-1), 'CENTER')])) story.append(div2_w) story.append(Spacer(1, 14)) story.append(Paragraph( 'For panel inquiries, project feasibility, or partnership opportunities, ' 'please reach out to our client services team.', styles['small_center'] )) story.append(Spacer(1, 6)) story.append(Paragraph( f'This document was generated on {data.get("generated_at", "")}.', ParagraphStyle('FootNote', fontName='Helvetica', fontSize=6.5, textColor=SLATE_500, alignment=TA_CENTER, leading=9) )) # ════════════════════════════════════════════ # BUILD # ════════════════════════════════════════════ doc.build(story, onFirstPage=draw_page, onLaterPages=draw_page) print(f'PDF generated: {output_path}') # ─── Main ─── if __name__ == '__main__': if len(sys.argv) != 3: print('Usage: python3 generate_panelbook.py input.json output.pdf') sys.exit(1) with open(sys.argv[1], 'r') as f: data = json.load(f) build_pdf(data, sys.argv[2]) -------------------- END OF FILE -------------------- FILE: Relevant Reflex Shop/index.php TYPE: PHP SIZE: 76.14 KB ------------------------------------------------------------ prepare("SELECT * FROM admin_users WHERE username = ? AND status = 'active'"); $stmt->execute([$username]); $user = $stmt->fetch(); if ($user && password_verify($password, $user['password'])) { $_SESSION['admin_id'] = $user['id']; $_SESSION['admin_username'] = $user['username']; $_SESSION['admin_email'] = $user['email']; $_SESSION['admin_role'] = $user['role']; $_SESSION['admin_name'] = $user['full_name']; $updateStmt = $pdo->prepare("UPDATE admin_users SET last_login = NOW() WHERE id = ?"); $updateStmt->execute([$user['id']]); logActivity($user['id'], 'login', 'User logged in successfully'); header('Location: index.php'); exit; } else { $error = 'Invalid username or password'; } } catch (Exception $e) { error_log("Login error: " . $e->getMessage()); $error = 'An error occurred. Please try again.'; } } } // ============ SHOW LOGIN FORM ============ ?>Admin Portal
Manage members, projects, clients, invoices, fieldwork, and survey operations from a single unified dashboard.
Sign in to your admin account to continue.
This is a secure admin area. All login attempts are logged and monitored. Unauthorized access is strictly prohibited.
·
| Project | Client | Status | Updated |
|---|---|---|---|
|
|
'green','Closed'=>'gray','On hold'=>'amber','Created'=>'blue','Targeted'=>'blue'][$p['status']] ?? 'gray'; ?> |
No projects yet
| Ticket | Type | Status | Updated |
|---|---|---|---|
|
|
'red','pending'=>'amber','resolved'=>'green','closed'=>'gray'][$t['status']] ?? 'gray'; ?> |
No tickets yet
| Admin | Action | Time (IST) |
|---|---|---|
No activity yet
Please ensure TCPDF is installed in the /tcpdf directory.
'); } require_once $tcpdfPath; $pdo = getDBConnection(); $settings = []; try { $result = $pdo->query("SELECT setting_key, setting_value FROM company_settings"); while ($row = $result->fetch()) { $settings[$row['setting_key']] = $row['setting_value']; } } catch (Exception $e) { die('Error loading settings.'); } $s = function($key, $default = '') use ($settings) { return $settings[$key] ?? $default; }; $addrParts = array_filter([ $s('company_address'), $s('company_city'), $s('company_state'), $s('company_country'), $s('company_pincode') ]); $fullAddr = implode(', ', $addrParts); // ─── Colors — all dark enough for reliable printing ─── $GREEN = [5, 150, 105]; $DARK = [15, 23, 42]; // near-black for primary text $BODY = [30, 41, 59]; // #1e293b — body text $SUB = [51, 65, 85]; // #334155 — secondary text (prints well) $MUTED = [71, 85, 105]; // #475569 — muted but still printable $RULE = [203, 213, 225]; // #cbd5e1 — lines $WHITE = [255, 255, 255]; class LetterheadPDF extends TCPDF { public function Header() {} public function Footer() {} } $pdf = new LetterheadPDF('P', 'mm', 'A4', true, 'UTF-8', false); $pdf->SetCreator('Relevant Reflex'); $pdf->SetAuthor($s('company_name', 'Relevant Reflex Consulting')); $pdf->SetTitle('Letterhead - ' . $s('company_name', 'Company')); $pdf->SetMargins(0, 0, 0); $pdf->SetAutoPageBreak(false, 0); $pdf->setPrintHeader(false); $pdf->setPrintFooter(false); $pdf->AddPage(); $PW = 210; $PH = 297; $LM = 20; $RM = 20; $CW = $PW - $LM - $RM; // Left column width (company name area) — stops at 55% to avoid overlap $LEFT_W = $CW * 0.52; // Right column starts at 58% — gives a gap $RIGHT_X = $LM + ($CW * 0.58); $RIGHT_W = $PW - $RM - $RIGHT_X; // ══════════════════════════════════════════════════ // TOP ACCENT — thin green strip // ══════════════════════════════════════════════════ $pdf->SetFillColor(...$GREEN); $pdf->Rect(0, 0, $PW, 1.2, 'F'); // ══════════════════════════════════════════════════ // LOGO — rounded green square with "RR" // ══════════════════════════════════════════════════ $logoX = $LM; $logoY = 14; $logoS = 15; $pdf->SetFillColor(...$GREEN); $pdf->RoundedRect($logoX, $logoY, $logoS, $logoS, 3.2, '1111', 'F'); $pdf->SetFont('helvetica', 'B', 16); $pdf->SetTextColor(...$WHITE); $pdf->SetXY($logoX, $logoY + 3.2); $pdf->Cell($logoS, $logoS - 6.4, 'RR', 0, 0, 'C'); // ══════════════════════════════════════════════════ // COMPANY NAME (left side, constrained width) // ══════════════════════════════════════════════════ $nameX = $logoX + $logoS + 5; $nameMaxW = $LEFT_W - $logoS - 5; // available width for name $pdf->SetFont('helvetica', 'B', 22); $pdf->SetTextColor(...$GREEN); $pdf->SetXY($nameX, $logoY + 1); $pdf->Cell($nameMaxW, 10, $s('company_name', 'Your Company Name'), 0, 1, 'L'); // ══════════════════════════════════════════════════ // TAGLINE (left side, constrained) // ══════════════════════════════════════════════════ $pdf->SetFont('helvetica', '', 6.5); $pdf->SetTextColor(...$MUTED); $pdf->SetXY($nameX, $logoY + 12); $pdf->Cell($nameMaxW, 4, 'PANEL MANAGEMENT & RESEARCH SOLUTIONS', 0, 1, 'L'); // ══════════════════════════════════════════════════ // CONTACT INFO — right column, no overlap // ══════════════════════════════════════════════════ $contactItems = []; if ($s('company_phone')) $contactItems[] = $s('company_phone'); if ($s('company_email')) $contactItems[] = $s('company_email'); if ($s('company_website')) $contactItems[] = str_replace(['https://','http://'], '', $s('company_website')); $contactStartY = $logoY + 1; $contactLineH = 6.5; foreach ($contactItems as $i => $text) { $y = $contactStartY + ($i * $contactLineH); // Contact text — right-aligned within right column $pdf->SetFont('helvetica', '', 9); $pdf->SetTextColor(...$BODY); $pdf->SetXY($RIGHT_X, $y); $pdf->Cell($RIGHT_W, $contactLineH, $text, 0, 0, 'R'); } // ══════════════════════════════════════════════════ // ADDRESS // ══════════════════════════════════════════════════ $addrY = $logoY + $logoS + 7; $pdf->SetFont('helvetica', '', 9); $pdf->SetTextColor(...$SUB); $pdf->SetXY($LM, $addrY); $pdf->MultiCell($CW * 0.65, 4.5, $fullAddr, 0, 'L'); // ══════════════════════════════════════════════════ // HEADER DIVIDER — solid green line // ══════════════════════════════════════════════════ $divY = $addrY + 14; $pdf->SetDrawColor(...$GREEN); $pdf->SetLineWidth(0.5); $pdf->Line($LM, $divY, $PW - $RM, $divY); // ══════════════════════════════════════════════════ // FOOTER // ══════════════════════════════════════════════════ $footerY = $PH - 18; // Separator $pdf->SetDrawColor(...$RULE); $pdf->SetLineWidth(0.2); $pdf->Line($LM, $footerY, $PW - $RM, $footerY); // Footer left $pdf->SetFont('helvetica', '', 8); $pdf->SetTextColor(...$MUTED); $footerLeft = $s('company_name', 'Company'); if ($s('company_city') || $s('company_state')) { $footerLeft .= ' · ' . $s('company_city', ''); if ($s('company_state')) $footerLeft .= ', ' . $s('company_state'); } $pdf->SetXY($LM, $footerY + 4); $pdf->Cell($CW * 0.65, 5, $footerLeft, 0, 0, 'L'); // Footer right if ($s('company_website')) { $pdf->SetXY($LM + ($CW * 0.65), $footerY + 4); $pdf->Cell($CW * 0.35, 5, str_replace(['https://','http://'], '', $s('company_website')), 0, 0, 'R'); } // ══════════════════════════════════════════════════ // BOTTOM ACCENT — thin green strip // ══════════════════════════════════════════════════ $pdf->SetFillColor(...$GREEN); $pdf->Rect(0, $PH - 1.2, $PW, 1.2, 'F'); // ══════════════════════════════════════════════════ // OUTPUT // ══════════════════════════════════════════════════ $filename = 'Letterhead - ' . $s('company_name', 'Company') . '.pdf'; $pdf->Output($filename, 'D'); -------------------- END OF FILE -------------------- FILE: Relevant Reflex Shop/login.php TYPE: PHP SIZE: 13.49 KB ------------------------------------------------------------ prepare("SELECT * FROM admin_users WHERE username = ? AND status = 'active'"); $stmt->execute([$username]); $user = $stmt->fetch(); if ($user && password_verify($password, $user['password'])) { // Set session $_SESSION['admin_id'] = $user['id']; $_SESSION['admin_username'] = $user['username']; $_SESSION['admin_email'] = $user['email']; $_SESSION['admin_role'] = $user['role']; $_SESSION['admin_name'] = $user['full_name']; // Update last login $updateStmt = $pdo->prepare("UPDATE admin_users SET last_login = NOW() WHERE id = ?"); $updateStmt->execute([$user['id']]); // Log activity logActivity($user['id'], 'login', 'User logged in successfully'); header('Location: index.php'); exit; } else { $error = 'Invalid username or password'; } } catch (Exception $e) { error_log("Login error: " . $e->getMessage()); $error = 'An error occurred. Please try again.'; } } } ?>Admin Portal
Manage members, projects, clients, invoices, fieldwork, and survey operations from a single unified dashboard.
Sign in to your admin account to continue.
This is a secure admin area. All login attempts are logged and monitored. Unauthorized access is strictly prohibited.
Update information for member
Complete information for member
| Request ID | Points | Amount (₹) | UPI ID | Status | Requested | Processed |
|---|---|---|---|---|---|---|
| ₹ | Pending'; ?> |
View and manage all registered survey panel members
| Member ID | Gender | Date of Birth | Postcode | SEC | Points | Status | Joined | Actions | |
|---|---|---|---|---|---|---|---|---|---|
|
No panel members found
|
|||||||||
|
Verified
|
diff($dob)->y;
?>
format('M j, Y'); ?>
years old
|
'#059669','B'=>'#0d9488','C'=>'#2563eb','D'=>'#d97706','E'=>'#dc2626']; $bgc = $secColors[$member['isec_class']] ?? '#94a3b8'; ?> — | |||||||
Welcome to India\'s Trusted Survey Platform
To activate your account and start earning through paid surveys, please verify your email address:
Note: This link expires in 48 hours.
If the button doesn\'t work: ' . $verifyUrl . '
Best regards,
The Relevant Reflex Team
Welcome to India\'s Trusted Survey Platform
To activate your account and start earning through paid surveys, please verify your email address:
Note: This link expires in 48 hours.
If the button doesn\'t work: ' . $verifyUrl . '
Best regards,
The Relevant Reflex Team
Manage all registered survey panel members
Sends a fresh 48-hour verification link to all members who registered in the selected date range and have not yet verified their email.
| ID | Gen | Date of Birth | Postcode | SEC | Points | Status | Joined | Actions | |
|---|---|---|---|---|---|---|---|---|---|
|
No panel members found
|
|||||||||
|
Verified
|
diff($dob)->y;
?>
format('d M Y'); ?>
y
|
'#059669','B'=>'#0d9488','C'=>'#2563eb','D'=>'#d97706','E'=>'#dc2626']; $bgc = $secColors[$member['isec_class']] ?? '#94a3b8'; ?> — | |||||||
`
2. **Update favicon**:
- Add your `favicon.ico` to the root directory
- Update the reference in `includes/header.php`
### Custom Styling
- **Main styles**: `assets/css/main.css`
- **Mobile styles**: `assets/css/responsive.css`
- **Dashboard styles**: `assets/css/dashboard.css`
## 📱 Mobile Optimization
The system is built mobile-first with:
- **Responsive Grid System**: Adapts to all screen sizes
- **Touch-Friendly Interface**: 44px minimum touch targets
- **Optimized Navigation**: Hamburger menu on mobile
- **Fast Loading**: Optimized assets and caching
- **Progressive Enhancement**: Works without JavaScript
## 🔧 Maintenance
### Regular Tasks
1. **Database Backups**: Weekly automated backups recommended
2. **Update Dependencies**: Keep PHP and MySQL updated
3. **Monitor Performance**: Check load times and optimize
4. **Security Updates**: Regular security audits
5. **Content Updates**: Keep information current
### Performance Optimization
1. **Enable Gzip Compression** (included in .htaccess)
2. **Optimize Images**: Use WebP format when possible
3. **Monitor Database**: Run `OPTIMIZE TABLE` monthly
4. **Cache Headers**: Properly configured in .htaccess
5. **CDN Integration**: Consider using a CDN for static assets
## 🔐 Security Features
- **SQL Injection Protection**: PDO prepared statements
- **XSS Prevention**: Input sanitization and CSP headers
- **CSRF Protection**: Session-based token validation
- **Secure Headers**: Comprehensive security headers
- **File Upload Security**: Restricted file types and locations
- **Access Control**: Role-based permissions
## 🆘 Troubleshooting
### Common Issues
**1. Database Connection Error**
```
Solution: Check config.php credentials and database server status
```
**2. Page Not Found (404)**
```
Solution: Verify .htaccess file is uploaded and mod_rewrite is enabled
```
**3. Slow Loading**
```
Solution: Enable compression, check hosting performance, optimize images
```
**4. Mobile Display Issues**
```
Solution: Clear browser cache, check responsive.css is loaded
```
**5. JavaScript Not Working**
```
Solution: Check browser console for errors, verify JS files are accessible
```
### Getting Help
1. **Check Error Logs**: In your hosting control panel
2. **Browser Console**: F12 to check for JavaScript errors
3. **PHP Error Display**: Temporarily enable in config.php for debugging
4. **Hosting Support**: Contact your hosting provider for server issues
## 📞 Support
For technical support and customization services:
- **Email**: support@relevantreflex.com
- **Documentation**: Check inline comments in code files
- **Updates**: Monitor for system updates and security patches
## 📝 License
This system is proprietary software developed for Relevant Reflex. All rights reserved.
## 🚀 Quick Start Checklist
- [ ] Create database in phpMyAdmin
- [ ] Import database_schema.sql
- [ ] Update config.php with database credentials
- [ ] Upload all files to web server
- [ ] Set correct file permissions
- [ ] Test login with admin/admin123
- [ ] Change default admin password
- [ ] Customize colors and branding
- [ ] Enable SSL and HTTPS redirect
- [ ] Test all functionality
- [ ] Setup regular backups
## Version Information
- **Version**: 1.0.0
- **Release Date**: September 2025
- **PHP Compatibility**: 7.4+
- **MySQL Compatibility**: 5.7+
- **Browser Support**: All modern browsers, IE11+
---
**Important**: Always backup your database and files before making changes or updates.
-------------------- END OF FILE --------------------
FILE: Relevant Reflex Shop/robots.txt
TYPE: TXT
SIZE: 2.16 KB
------------------------------------------------------------
# Relevant Reflex Panel Management System
# Robots.txt file for search engine optimization
User-agent: *
# Allow access to main pages
Allow: /
Allow: /index.php
Allow: /users.php
Allow: /panel.php
Allow: /supply.php
Allow: /demand.php
Allow: /finance.php
Allow: /support.php
Allow: /settings.php
# Allow access to static assets
Allow: /assets/css/
Allow: /assets/js/
Allow: /assets/images/
# Disallow sensitive files and directories
Disallow: /config.php
Disallow: /database_schema.sql
Disallow: /.htaccess
Disallow: /includes/
Disallow: /logs/
Disallow: /backups/
Disallow: /temp/
Disallow: /cache/
Disallow: /admin/
Disallow: /api/
Disallow: /private/
# Disallow URL parameters that might create duplicate content
Disallow: /*?*
Disallow: /*&*
Disallow: /*/search?*
Disallow: /*/filter?*
# Disallow error pages
Disallow: /error-*
Disallow: /404.html
Disallow: /500.html
Disallow: /maintenance.html
# Block access to development and testing files
Disallow: /test/
Disallow: /dev/
Disallow: /staging/
Disallow: /*.bak
Disallow: /*.tmp
Disallow: /*.log
# Block common exploits and security probes
Disallow: /wp-admin/
Disallow: /wordpress/
Disallow: /wp-content/
Disallow: /admin.php
Disallow: /administrator/
Disallow: /phpmyadmin/
Disallow: /phpMyAdmin/
# Block unwanted file types
Disallow: /*.sql$
Disallow: /*.zip$
Disallow: /*.tar.gz$
Disallow: /*.bak$
Disallow: /*.conf$
Disallow: /*.ini$
# Sitemap location
Sitemap: https://yourdomain.com/sitemap.xml
# Crawl delay for respectful crawling (optional)
# Crawl-delay: 1
# Specific rules for different bots (optional)
# Google Bot - allow everything we want indexed
User-agent: Googlebot
Allow: /
Disallow: /config.php
Disallow: /includes/
Disallow: /*?*
# Bing Bot
User-agent: Bingbot
Allow: /
Disallow: /config.php
Disallow: /includes/
# Block aggressive bots that might overload the server
User-agent: AhrefsBot
Disallow: /
User-agent: MJ12bot
Disallow: /
User-agent: SemrushBot
Disallow: /
User-agent: DotBot
Disallow: /
# Allow social media bots for link previews
User-agent: facebookexternalhit
Allow: /
User-agent: Twitterbot
Allow: /
User-agent: LinkedInBot
Allow: /
# Note: Update "yourdomain.com" with your actual domain name
-------------------- END OF FILE --------------------
FILE: Relevant Reflex Shop/settings.php
TYPE: PHP
SIZE: 28.63 KB
------------------------------------------------------------
exec("
CREATE TABLE IF NOT EXISTS company_settings (
id INT AUTO_INCREMENT PRIMARY KEY,
setting_key VARCHAR(100) UNIQUE NOT NULL,
setting_value TEXT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
");
} catch (Exception $e) {
// Table might already exist
}
// Handle form submission
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_settings'])) {
try {
$fields = [
'company_name', 'company_address', 'company_city', 'company_state',
'company_country', 'company_pincode', 'company_phone', 'company_email',
'company_website',
'tax_gst', 'tax_pan', 'tax_cin', 'tax_sac_code',
'bank_name', 'bank_account_name', 'bank_account_number', 'bank_ifsc',
'bank_branch', 'bank_swift',
'invoice_prefix', 'invoice_terms', 'invoice_notes', 'invoice_footer'
];
$stmt = $pdo->prepare("
INSERT INTO company_settings (setting_key, setting_value, updated_at)
VALUES (?, ?, NOW())
ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value), updated_at = NOW()
");
foreach ($fields as $field) {
$value = trim($_POST[$field] ?? '');
$stmt->execute([$field, $value]);
}
$success = 'Company settings saved successfully!';
$mode = 'view';
logActivity($_SESSION['admin_id'], 'update', 'Updated company invoicing settings', 'settings', null);
} catch (Exception $e) {
$error = 'Error saving settings: ' . $e->getMessage();
$mode = 'edit';
}
}
// Load current settings
$settings = [];
try {
$result = $pdo->query("SELECT setting_key, setting_value FROM company_settings");
while ($row = $result->fetch()) {
$settings[$row['setting_key']] = $row['setting_value'];
}
} catch (Exception $e) {}
function getSetting($key, $default = '') {
global $settings;
return $settings[$key] ?? $default;
}
$hasData = !empty(array_filter($settings));
include 'includes/header.php';
?>
Manage your company details used in client invoicing
Add your company information for invoicing by switching to Edit mode.
✏ Add Company DetailsBasic company details that appear on invoices and official documents.
Tax identification numbers and registration details.
Banking information displayed on invoices for client payments.
Default text and formatting for generated invoices.
Manage affiliate partners and track signups
| ID | Affiliate Code | Company/Name | Type | In-charge | Location | Contact | Hits | Not Verified | Verified | Balance | Status | Actions |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| No affiliates found. Click "Add New Affiliate" to create one. | ||||||||||||
| # |
-
|
₹ | ||||||||||
Our support portal is available on the main Relevant Reflex website. Submit tickets, track requests, and access help resources all in one place.
Open Support Portal →Opens in a new window at relevantreflex.com
Manage admin users and their access roles
| ID | User Details | Role | Status | Last Login | Actions | |
|---|---|---|---|---|---|---|
| # |
|
Never | Current User |