All files / src/components/features/support/FAQ ArticleView.tsx

0% Statements 0/160
100% Branches 0/0
0% Functions 0/1
0% Lines 0/160

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161                                                                                                                                                                                                                                                                                                                                 
'use client';

/**
 * ArticleView - Full article page component
 */

import React, { useState } from 'react';
import Link from 'next/link';
import { clientLogger } from '@/lib/logging/clientLogger';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import { SupportArticle } from '@/types/support';
import { Icon } from '@/components/ui/icons';

export interface ArticleViewProps {
  /** The article to display */
  article: SupportArticle;
}

export default function ArticleView({ article }: ArticleViewProps) {
  const [hasVoted, setHasVoted] = useState(false);
  const [voteSubmitting, setVoteSubmitting] = useState(false);

  const handleVote = async (helpful: boolean) => {
    if (hasVoted || voteSubmitting) return;

    setVoteSubmitting(true);
    try {
      const response = await fetch(`/api/support/articles/${article.slug}/helpful`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ helpful })});

      if (response.ok) {
        setHasVoted(true);
      }
    } catch (error) {
      clientLogger.error('Failed to submit vote', error instanceof Error ? error : new Error(String(error)), {
        articleSlug: article.slug,
        helpful
      });
    } finally {
      setVoteSubmitting(false);
    }
  };

  return (
    <div className="pt-[160px] sm:pt-[120px] lg:pt-[95px] xl:pt-[110px]">
      <div className="max-w-3xl mx-auto px-4 py-8">
      {/* Breadcrumb */}
      <nav className="flex items-center gap-2 text-sm text-gray-500 mb-6">
        <Link href="/support" className="hover:text-gray-700">
          Support
        </Link>
        <span>/</span>
        <Link href="/support/articles" className="hover:text-gray-700">
          Help Center
        </Link>
        <span>/</span>
        <span className="text-gray-900">{article.category}</span>
      </nav>

      {/* Article */}
      <article className="bg-white rounded-lg border border-gray-200 p-8">
        {/* Category Badge */}
        <span className="inline-block px-2 py-0.5 text-xs font-medium bg-blue-100 text-blue-700 rounded mb-4">
          {article.category}
        </span>

        {/* Title */}
        <h1 className="text-3xl font-bold text-gray-900 mb-4">
          {article.title}
        </h1>

        {/* Meta */}
        <div className="flex items-center gap-4 text-sm text-gray-500 mb-8 pb-8 border-b border-gray-200">
          <span>
            Last updated:{' '}
            {new Date(article.updatedAt).toLocaleDateString('en-US', {
              month: 'long',
              day: 'numeric',
              year: 'numeric'})}
          </span>
          <span>{article.viewCount} views</span>
        </div>

        {/* Content */}
        <div className="prose prose-blue max-w-none">
          <ReactMarkdown remarkPlugins={[remarkGfm]}>
            {article.content}
          </ReactMarkdown>
        </div>

        {/* Feedback Section */}
        <div className="mt-8 pt-8 border-t border-gray-200">
          {!hasVoted ? (
            <div>
              <p className="text-gray-700 mb-4">Was this article helpful?</p>
              <div className="flex gap-3">
                <button
                  type="button"
                  onClick={() => handleVote(true)}
                  disabled={voteSubmitting}
                  className="
                    inline-flex items-center gap-2 px-4 py-2
                    border border-gray-300 rounded-lg
                    text-gray-700 hover:bg-gray-50
                    disabled:opacity-50
                    transition-colors
                  "
                >
                  <Icon name="thumb-up" size={20} />
                  Yes, it helped
                </button>
                <button
                  type="button"
                  onClick={() => handleVote(false)}
                  disabled={voteSubmitting}
                  className="
                    inline-flex items-center gap-2 px-4 py-2
                    border border-gray-300 rounded-lg
                    text-gray-700 hover:bg-gray-50
                    disabled:opacity-50
                    transition-colors
                  "
                >
                  <Icon name="thumb-down" size={20} />
                  No, I need more help
                </button>
              </div>
            </div>
          ) : (
            <div className="bg-green-50 text-green-700 px-4 py-3 rounded-lg">
              Thank you for your feedback!
            </div>
          )}
        </div>

        {/* Still need help? */}
        <div className="mt-8 p-6 bg-gray-50 rounded-lg text-center">
          <h3 className="font-semibold text-gray-900 mb-2">
            Still need help?
          </h3>
          <p className="text-gray-600 mb-4">
            Our support team is ready to assist you.
          </p>
          <Link
            href="/support/tickets/new"
            className="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
          >
            Contact Support
          </Link>
        </div>
      </article>

      {/* Related Articles would go here */}
      </div>
    </div>
  );
}